Skip to content

Property hooks #82

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 71 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
5ff244d
[skip ci] Fix linguist-generated for zend_vm_opcodes files
iluuu1994 May 24, 2023
eb7ec15
Use single allocation for indirect values in array_multisort
iluuu1994 May 24, 2023
150825d
[skip ci] Fix release date of PHP 8.2.7
adoy May 25, 2023
04b1bc3
Merge branch 'PHP-8.2'
adoy May 25, 2023
8946b7b
Access violation when ALLOC_FALLBACK fixed
KoudelkaB May 24, 2023
5b8e941
Merge branch 'PHP-8.1' into PHP-8.2
iluuu1994 May 25, 2023
adb3d52
Merge branch 'PHP-8.2'
iluuu1994 May 25, 2023
cba335d
Fix GH-11288 and GH-11289 and GH-11290 and GH-9142: DOMExceptions and…
nielsdos May 22, 2023
af72727
Merge branch 'PHP-8.1' into PHP-8.2
nielsdos May 25, 2023
56b1c11
Merge branch 'PHP-8.2'
nielsdos May 25, 2023
5b033b0
Fix zend_jit_stop_counter_handlers() performance issues with protect_…
iluuu1994 May 25, 2023
2d86e95
Merge branch 'PHP-8.2'
iluuu1994 May 26, 2023
b5a07a7
[skip ci] Fix race condition in readline test
iluuu1994 May 26, 2023
b47a7d4
Merge branch 'PHP-8.1' into PHP-8.2
iluuu1994 May 26, 2023
58a191c
Merge branch 'PHP-8.2'
iluuu1994 May 26, 2023
8ed66b4
Add tests for list() in assignment in array literals
iluuu1994 May 25, 2023
fbe6696
Revert "Use zend_ast_apply in zend_eval_const_expr (#11261)"
iluuu1994 May 26, 2023
1dfa277
Fix GCC 12 compilation on riscv64
danog May 25, 2023
350e449
Merge branch 'PHP-8.1' into PHP-8.2
devnexen May 27, 2023
2e4369a
Merge branch 'PHP-8.2'
devnexen May 27, 2023
f249958
[skip ci] Add more patterns to run-tests.php retry list
iluuu1994 May 27, 2023
f735543
Merge branch 'PHP-8.1' into PHP-8.2
iluuu1994 May 27, 2023
2d883a6
Merge branch 'PHP-8.2'
iluuu1994 May 27, 2023
b884011
Shrink libxml_doc_props struct (#11326)
nielsdos May 29, 2023
c473787
Fix GH-10234: Setting DOMAttr::textContent results in an empty attrib…
nielsdos Jan 6, 2023
9ff1ea6
Merge branch 'PHP-8.1' into PHP-8.2
nielsdos May 29, 2023
99ec0c1
Merge branch 'PHP-8.2'
nielsdos May 29, 2023
b495a91
Add string output escaping into zend dump (phpdbg + opcache debug) (#…
SerafimArts May 29, 2023
761b9a4
Fix return value in stub file for DOMNodeList::item
divinity76 May 29, 2023
dfa8987
Merge branch 'PHP-8.1' into PHP-8.2
nielsdos May 29, 2023
f90962d
Merge branch 'PHP-8.2'
nielsdos May 29, 2023
bce5360
Fix GH-11338: SplFileInfo empty getBasename with more than one slash
nielsdos May 29, 2023
9c59d22
Fix GH-11336: php still tries to unlock the shared memory ZendSem wit…
nielsdos May 29, 2023
154c251
Fix spec compliance error for DOMDocument::getElementsByTagNameNS
nielsdos May 29, 2023
b374ec3
Fix DOMElement::append() and DOMElement::prepend() hierarchy checks
nielsdos May 29, 2023
0e7ad40
Merge branch 'PHP-8.1' into PHP-8.2
nielsdos May 30, 2023
1ed6868
Merge branch 'PHP-8.2'
nielsdos May 30, 2023
d8102e6
Remove unnecessary tree setting in dom_zvals_to_fragment()
nielsdos May 29, 2023
c6655fb
Implement dom_get_doc_props_read_only()
nielsdos May 29, 2023
c50172e
Fix mb_strlen is wrong length for CP932 when 0x80.
youkidearitai May 29, 2023
c33589e
Merge branch 'PHP-8.1' into PHP-8.2
alexdowad May 30, 2023
6930ef5
Merge branch 'PHP-8.2'
alexdowad May 30, 2023
c6ae7a5
Fix bug GH-11246 cli/get_set_process_title
lucasnetau May 16, 2023
0bf8ecf
Merge branch 'PHP-8.1' into PHP-8.2
iluuu1994 May 31, 2023
bb48f5d
Merge branch 'PHP-8.2'
iluuu1994 May 31, 2023
7812772
Fix GH-11347: Memory leak when calling a static method inside an xpat…
nielsdos May 30, 2023
8126bea
Merge branch 'PHP-8.1' into PHP-8.2
nielsdos May 31, 2023
91fd564
Merge branch 'PHP-8.2'
nielsdos May 31, 2023
82e761e
Fix [-Wenum-int-mismatch] compiler warnings (#11352)
Girgias Jun 1, 2023
1540245
ext/standard/array.c: Optimize min/max functions for int/float (#11194)
Girgias Jun 2, 2023
f8faa8b
Use zval_ptr_dtor_nogc() for callable in ext/xslt (#11356)
nielsdos Jun 2, 2023
79128af
[skip ci] Update release process to publish php-keyring.gpg in web-php
adoy Jun 2, 2023
810507a
http_fopen_wrapper: fix [-Wanalyzer-deref-before-check]
Girgias Jun 2, 2023
13ad8ef
memory stream: fix [-Wanalyzer-deref-before-check]
Girgias Jun 2, 2023
c5d7264
Fix file descriptor check
Girgias Jun 2, 2023
ce724d1
Assert zend_constant exist
Girgias Jun 2, 2023
c3f0797
Implement iteration cache, item cache and length cache for node list …
nielsdos Jun 2, 2023
5fae4b5
Struct-pack spl_dllist_object
nielsdos Jun 3, 2023
c6bffff
Remove dead code from sxe_get_element_by_name()
nielsdos Jun 2, 2023
7951279
Remove double class entry variable
nielsdos Jun 2, 2023
47c277b
Use xmlStrEqual() instead of !xmlStrCmp()
nielsdos Jun 2, 2023
ed097e3
No need for the double name pointer
nielsdos Jun 2, 2023
3da4156
Switch DOMNodeList::item() and DOMNamedNodeMap::item() to fast ZPP (#…
nielsdos Jun 4, 2023
b1d8e24
Fix bug #67440: append_node of a DOMDocumentFragment does not reconci…
nielsdos Jun 3, 2023
23f7002
Fix bug #81642: DOMChildNode::replaceWith() bug when replacing a node…
nielsdos Jun 3, 2023
0e34ac8
Fix bug #77686: Removed elements are still returned by getElementById
nielsdos Jun 4, 2023
5b79c53
Merge branch 'PHP-8.1' into PHP-8.2
nielsdos Jun 4, 2023
e8fb0ed
Merge branch 'PHP-8.2'
nielsdos Jun 4, 2023
4d4a5ab
Accessors implementation
iluuu1994 Apr 20, 2023
62369cc
Basic json_encode support
iluuu1994 Jun 6, 2023
1137c18
Implement get_object_vars
iluuu1994 Jun 6, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
# Collapse generated files within a pull request.
**/*_arginfo.h linguist-generated
/Zend/zend_vm_execute.h linguist-generated
/Zend/zend_vm_opcodes.{h,c} linguist-generated
/Zend/zend_vm_opcodes.[ch] linguist-generated

# The OSS fuzz files are bunary
/ext/date/tests/ossfuzz*.txt binary
3 changes: 3 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ PHP NEWS
- Date:
. Implement More Appropriate Date/Time Exceptions RFC. (Derick)

- DOM:
. Fix bug GH-11308 (getElementsByTagName() is O(N^2)). (nielsdos)

- Exif:
. Removed unneeded codepaths in exif_process_TIFF_in_JPEG(). (nielsdos)

Expand Down
23 changes: 23 additions & 0 deletions UPGRADING.INTERNALS
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,29 @@ PHP 8.3 INTERNALS UPGRADE NOTES
- The PHPAPI spl_iterator_apply() function now returns zend_result instead of int.
There are no functional changes.

f. ext/dom
- A new function dom_get_doc_props_read_only() is added to gather the document
properties in a read-only way. This function avoids allocation when there are
no document properties changed yet.
- The node list returned by DOMNode::getElementsByTagName() and
DOMNode::getElementsByTagNameNS() now caches the length and the last requested item.
This means that the length and the last requested item are not recalculated
when the node list is iterated over multiple times.
If you do not use the internal PHP dom APIs to modify the document, you need to
manually invalidate the cache using php_libxml_invalidate_node_list_cache_from_doc().
Furthermore, the following internal APIs were added to handle the cache:
. php_dom_is_cache_tag_stale_from_doc_ptr()
. php_dom_is_cache_tag_stale_from_node()
. php_dom_mark_cache_tag_up_to_date_from_node()
- The function dom_get_elements_by_tag_name_ns_raw() has an additional parameter to indicate
the base node of the node list. This function also no longer accepts -1 as the index argument.
- The function dom_namednode_iter() has additional arguments to avoid recomputing the length of
the strings.

g. ext/libxml
- Two new functions: php_libxml_invalidate_node_list_cache_from_doc() and
php_libxml_invalidate_node_list_cache() were added to invalidate the cache of a node list.

========================
4. OpCode changes
========================
Expand Down
3 changes: 3 additions & 0 deletions Zend/Optimizer/compact_literals.c
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,9 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
LITERAL_INFO(opline->op2.constant, 2);
}
break;
case ZEND_INIT_PARENT_PROPERTY_HOOK_CALL:
LITERAL_INFO(opline->op1.constant, 1);
break;
case ZEND_CATCH:
LITERAL_INFO(opline->op1.constant, 2);
break;
Expand Down
8 changes: 8 additions & 0 deletions Zend/Optimizer/optimize_func_calls.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ static void zend_delete_call_instructions(zend_op_array *op_array, zend_op *opli
case ZEND_INIT_STATIC_METHOD_CALL:
case ZEND_INIT_METHOD_CALL:
case ZEND_INIT_FCALL:
case ZEND_INIT_PARENT_PROPERTY_HOOK_CALL:
if (call == 0) {
MAKE_NOP(opline);
return;
Expand Down Expand Up @@ -95,6 +96,11 @@ static void zend_try_inline_call(zend_op_array *op_array, zend_op *fcall, zend_o
return;
}

if (fcall->opcode == ZEND_INIT_PARENT_PROPERTY_HOOK_CALL) {
/* Don't inline property hook method */
return;
}

for (i = 0; i < num_args; i++) {
/* Don't inline functions with by-reference arguments. This would require
* correct handling of INDIRECT arguments. */
Expand Down Expand Up @@ -168,6 +174,7 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx)
case ZEND_INIT_METHOD_CALL:
case ZEND_INIT_FCALL:
case ZEND_NEW:
case ZEND_INIT_PARENT_PROPERTY_HOOK_CALL:
/* The argument passing optimizations are valid for prototypes as well,
* as inheritance cannot change between ref <-> non-ref arguments. */
call_stack[call].func = zend_optimizer_get_called_func(
Expand Down Expand Up @@ -211,6 +218,7 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx)
}
} else if (fcall->opcode == ZEND_INIT_STATIC_METHOD_CALL
|| fcall->opcode == ZEND_INIT_METHOD_CALL
|| fcall->opcode == ZEND_INIT_PARENT_PROPERTY_HOOK_CALL
|| fcall->opcode == ZEND_NEW) {
/* We don't have specialized opcodes for this, do nothing */
} else {
Expand Down
1 change: 1 addition & 0 deletions Zend/Optimizer/zend_call_graph.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ ZEND_API void zend_analyze_calls(zend_arena **arena, zend_script *script, uint32
case ZEND_INIT_FCALL:
case ZEND_INIT_METHOD_CALL:
case ZEND_INIT_STATIC_METHOD_CALL:
case ZEND_INIT_PARENT_PROPERTY_HOOK_CALL:
call_stack[call] = call_info;
func = zend_optimizer_get_called_func(
script, op_array, opline, &is_prototype);
Expand Down
9 changes: 7 additions & 2 deletions Zend/Optimizer/zend_dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "zend_func_info.h"
#include "zend_call_graph.h"
#include "zend_dump.h"
#include "ext/standard/php_string.h"

void zend_dump_ht(HashTable *ht)
{
Expand Down Expand Up @@ -65,8 +66,12 @@ void zend_dump_const(const zval *zv)
case IS_DOUBLE:
fprintf(stderr, " float(%g)", Z_DVAL_P(zv));
break;
case IS_STRING:
fprintf(stderr, " string(\"%s\")", Z_STRVAL_P(zv));
case IS_STRING:;
zend_string *escaped_string = php_addcslashes(Z_STR_P(zv), "\"\\", 2);

fprintf(stderr, " string(\"%s\")", ZSTR_VAL(escaped_string));

zend_string_release(escaped_string);
break;
case IS_ARRAY:
fprintf(stderr, " array(...)");
Expand Down
33 changes: 33 additions & 0 deletions Zend/Optimizer/zend_optimizer.c
Original file line number Diff line number Diff line change
Expand Up @@ -910,6 +910,27 @@ zend_function *zend_optimizer_get_called_func(
}
}
break;
case ZEND_INIT_PARENT_PROPERTY_HOOK_CALL:;
zend_class_entry *scope = op_array->scope;
ZEND_ASSERT(scope != NULL);
if (scope && (scope->ce_flags & ZEND_ACC_LINKED) && scope->parent) {
zend_class_entry *parent_scope = scope->parent;
zend_string *prop_name = Z_STR_P(CRT_CONSTANT(opline->op1));
zend_property_hook_kind hook_kind = opline->op2.num;
zend_property_info *prop_info = zend_get_property_info(parent_scope, prop_name, /* silent */ true);

if (prop_info
&& prop_info != ZEND_WRONG_PROPERTY_INFO
&& !(prop_info->flags & ZEND_ACC_PRIVATE)
&& prop_info->hooks) {
zend_function *fbc = prop_info->hooks[hook_kind];
if (fbc) {
*is_prototype = true;
return fbc;
}
}
}
break;
case ZEND_NEW:
{
zend_class_entry *ce = zend_optimizer_get_class_entry_from_op1(
Expand Down Expand Up @@ -1425,6 +1446,7 @@ void zend_foreach_op_array(zend_script *script, zend_op_array_func_t func, void
{
zval *zv;
zend_op_array *op_array;
zend_property_info *property;

zend_foreach_op_array_helper(&script->main_op_array, func, context);

Expand All @@ -1445,6 +1467,17 @@ void zend_foreach_op_array(zend_script *script, zend_op_array_func_t func, void
zend_foreach_op_array_helper(op_array, func, context);
}
} ZEND_HASH_FOREACH_END();
ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, property) {
zend_function **hooks = property->hooks;
if (hooks) {
for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
zend_function *hook = hooks[i];
if (hook && hook->common.scope == ce) {
zend_foreach_op_array_helper(&hooks[i]->op_array, func, context);
}
}
}
} ZEND_HASH_FOREACH_END();
} ZEND_HASH_FOREACH_END();
}

Expand Down
20 changes: 20 additions & 0 deletions Zend/tests/accessors/final.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
--TEST--
Final accessors
--FILE--
<?php

class A {
public $prop {
final get { return 42; }
}
}

class B extends A {
public $prop {
get { return 24; }
}
}

?>
--EXPECTF--
Fatal error: Cannot override final accessor A::$prop::get() in %s on line %d
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ const FOO_COMPILE_ERROR = "BAR"{0};
var_dump(FOO_COMPILE_ERROR);
?>
--EXPECTF--
Fatal error: Array and string offset access syntax with curly braces is no longer supported in %s on line 2
Parse error: syntax error, unexpected token "{", expecting "," or ";" in %s on line %d
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ $foo = 'BAR';
var_dump($foo{0});
?>
--EXPECTF--
Fatal error: Array and string offset access syntax with curly braces is no longer supported in %s on line 3
Parse error: syntax error, unexpected token "{", expecting ")" in %s on line %d
2 changes: 1 addition & 1 deletion Zend/tests/alternative_offset_syntax_in_encaps_string.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ Alternative offset syntax should emit only E_COMPILE_ERROR in string interpolati
--FILE--
<?php "{$g{'h'}}"; ?>
--EXPECTF--
Fatal error: Array and string offset access syntax with curly braces is no longer supported in %s on line 1
Parse error: syntax error, unexpected token "{", expecting "->" or "?->" or "[" in %s on line %d
2 changes: 1 addition & 1 deletion Zend/tests/errmsg_037.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ class test {
echo "Done\n";
?>
--EXPECTF--
Fatal error: Cannot use the abstract modifier on a property in %s on line %d
Fatal error: Only hooked properties may be declared abstract in %s on line %d
13 changes: 0 additions & 13 deletions Zend/tests/errmsg_038.phpt

This file was deleted.

28 changes: 28 additions & 0 deletions Zend/tests/gh11320_1.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
--TEST--
GH-11320: Array literals can contain list() assignments
--FILE--
<?php
$index = 1;
function getList() { return [2, 3]; }
var_dump([$index => list($x, $y) = getList()]);
var_dump([$index => [$x, $y] = getList()]);
?>
--EXPECT--
array(1) {
[1]=>
array(2) {
[0]=>
int(2)
[1]=>
int(3)
}
}
array(1) {
[1]=>
array(2) {
[0]=>
int(2)
[1]=>
int(3)
}
}
12 changes: 12 additions & 0 deletions Zend/tests/gh11320_2.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
--TEST--
GH-11320: list() expressions can contain magic constants
--FILE--
<?php
[list(__FILE__ => $foo) = [__FILE__ => 'foo']];
var_dump($foo);
[[__FILE__ => $foo] = [__FILE__ => 'foo']];
var_dump($foo);
?>
--EXPECT--
string(3) "foo"
string(3) "foo"
8 changes: 8 additions & 0 deletions Zend/tests/gh11320_3.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
--TEST--
GH-11320: list() must not appear as a standalone array element
--FILE--
<?php
[list($a)];
?>
--EXPECTF--
Fatal error: Cannot use list() as standalone expression in %s on line %d
22 changes: 22 additions & 0 deletions Zend/tests/property_hooks/abstract_hook.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
--TEST--
Abstract hooks compile successfully
--FILE--
<?php

abstract class A {
public $prop {
abstract get;
set {}
}
}

class B extends A {
public $prop {
get {}
}
}

?>
===DONE===
--EXPECT--
===DONE===
15 changes: 15 additions & 0 deletions Zend/tests/property_hooks/abstract_hook_in_non_abstract_class.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
--TEST--
Abstract hooks in non-abstract class gives an error
--FILE--
<?php

class Test {
public $prop {
abstract get;
set {}
}
}

?>
--EXPECTF--
Fatal error: Class Test contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (Test::$prop::get) in %s on line %d
17 changes: 17 additions & 0 deletions Zend/tests/property_hooks/abstract_hook_not_implemented.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
--TEST--
Abstract hooks that are not implemented throw an error
--FILE--
<?php

abstract class A {
public $prop {
abstract get;
set {}
}
}

class B extends A {}

?>
--EXPECTF--
Fatal error: Class B contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (A::$prop::get) in %s on line %d
12 changes: 12 additions & 0 deletions Zend/tests/property_hooks/abstract_prop_abstract_hook.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
--TEST--
Abstract property with abstract hook is redundant so invalid
--FILE--
<?php

class C {
abstract public $prop { abstract get; }
}

?>
--EXPECTF--
Fatal error: Property hook on abstract property cannot be explicitly abstract in %s on line %d
17 changes: 17 additions & 0 deletions Zend/tests/property_hooks/abstract_prop_hooks.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
--TEST--
Explicit hooked property satisfies abstract property
--FILE--
<?php

abstract class A {
abstract public $prop { get; set; }
}

class B extends A {
public $prop { get {} set {} }
}

?>
===DONE===
--EXPECT--
===DONE===
14 changes: 14 additions & 0 deletions Zend/tests/property_hooks/abstract_prop_not_implemented.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
--TEST--
Abstract property not implemented throws an error
--FILE--
<?php

class A {
abstract public $prop { get; set; }
}

class B extends A {}

?>
--EXPECTF--
Fatal error: Class A contains 2 abstract methods and must therefore be declared abstract or implement the remaining methods (A::$prop::get, A::$prop::set) in %s on line %d
Loading