diff --git a/Zend/Optimizer/escape_analysis.c b/Zend/Optimizer/escape_analysis.c index 3c2864d14fb4..46597ddc5e9e 100644 --- a/Zend/Optimizer/escape_analysis.c +++ b/Zend/Optimizer/escape_analysis.c @@ -175,6 +175,9 @@ static bool is_allocation_def(zend_op_array *op_array, zend_ssa *ssa, int def, i && !ce->__set && !ce->__isset && !ce->num_hooked_props + /* ArrayAccess methods receive the object, interfaces of unlinked classes are unknown */ + && !ce->arrayaccess_funcs_ptr + && ((ce->ce_flags & ZEND_ACC_LINKED) || !ce->num_interfaces) && !(ce->ce_flags & forbidden_flags) && (ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) { return 1; diff --git a/ext/opcache/tests/opt/escape_analysis_array_access.phpt b/ext/opcache/tests/opt/escape_analysis_array_access.phpt new file mode 100644 index 000000000000..2864d3e4b2f5 --- /dev/null +++ b/ext/opcache/tests/opt/escape_analysis_array_access.phpt @@ -0,0 +1,51 @@ +--TEST-- +Escape analysis: objects implementing ArrayAccess escape through dimension accesses +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +--EXTENSIONS-- +opcache +--FILE-- +x = 3; return true; } + function offsetGet($o): mixed { $this->x = 2; return 42; } + function offsetSet($o, $v): void { $this->x = 4; } + function offsetUnset($o): void {} + + static function fetch() { + $o = new self; + $o->x = 1; + $o[0]; + return $o->x; + } + + static function isset() { + $o = new self; + $o->x = 1; + return [isset($o[0]), $o->x]; + } + + static function assign() { + $o = new self; + $o->x = 1; + $o[0] = 1; + return $o->x; + } +} + +var_dump(AA::fetch()); +var_dump(AA::isset()); +var_dump(AA::assign()); +?> +--EXPECT-- +int(2) +array(2) { + [0]=> + bool(true) + [1]=> + int(3) +} +int(4)