// is deprecated
RFC: https://wiki.php.net/rfc/deprecate_null_to_scalar_internal_arg
+ . When a method using static variables is inherited, the inherited method
+ will now initialize the static variables to their original values, rather
+ than the values at the time of inheritance:
+
+ class A {
+ public function counter() {
+ static $counter = 0;
+ $counter++;
+ return $counter;
+ }
+ }
+
+ var_dump((new A)->counter()); // int(1)
+
+ eval('class B extends A {}'); // eval() to prevent early binding.
+
+ var_dump((new B)->counter()); // int(1), previously int(2)
+ var_dump((new A)->counter()); // int(2)
+ var_dump((new B)->counter()); // int(2), previously int(3)
+
+ Previously the behavior would be different depending on whether A::counter()
+ was called before class B was declared, or after it was declared.
- Fileinfo:
. The fileinfo functions now accept and return, respectively, finfo objects
var_dump($c->foo());
?>
--EXPECT--
-array(1) {
- [0]=>
- int(42)
-}
+NULL
array(1) {
[0]=>
int(24)
var_dump($c->foo());
?>
--EXPECT--
-array(1) {
- [0]=>
- object(stdClass)#2 (0) {
- }
-}
+NULL
array(1) {
[0]=>
int(24)
--- /dev/null
+--TEST--
+Closure::bindTo() should preserve used variables
+--FILE--
+<?php
+
+$var = 0;
+$fn = function() use($var) {
+ var_dump($var);
+};
+$fn();
+$fn = $fn->bindTo(null, null);
+$fn();
+
+?>
+--EXPECT--
+int(0)
+int(0)
--FILE--
<?php
-/* The current behavior is probably a bug, but we should still test how it currently works. */
-
class Foo {
public static function test() {
static $i = 0;
--EXPECT--
int(1)
int(2)
+int(1)
int(2)
-int(3)
}
/* }}} */
+void zend_init_static_variables_map_ptr(zend_op_array *op_array)
+{
+ if (op_array->static_variables) {
+ ZEND_MAP_PTR_INIT(op_array->static_variables_ptr,
+ zend_arena_alloc(&CG(arena), sizeof(HashTable *)));
+ ZEND_MAP_PTR_SET(op_array->static_variables_ptr, NULL);
+ }
+}
+
ZEND_API void function_add_ref(zend_function *function) /* {{{ */
{
if (function->type == ZEND_USER_FUNCTION) {
zend_op_array *op_array = &function->op_array;
-
if (op_array->refcount) {
(*op_array->refcount)++;
}
- if (op_array->static_variables
- && !(GC_FLAGS(op_array->static_variables) & IS_ARRAY_IMMUTABLE)) {
- GC_ADDREF(op_array->static_variables);
- }
if (CG(compiler_options) & ZEND_COMPILE_PRELOAD) {
ZEND_ASSERT(op_array->fn_flags & ZEND_ACC_PRELOADED);
ZEND_MAP_PTR_NEW(op_array->run_time_cache);
- ZEND_MAP_PTR_NEW(op_array->static_variables_ptr);
} else {
- ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, &op_array->static_variables);
- ZEND_MAP_PTR_INIT(op_array->run_time_cache, zend_arena_alloc(&CG(arena), sizeof(void*)));
+ ZEND_MAP_PTR_INIT(op_array->run_time_cache, zend_arena_alloc(&CG(arena), sizeof(void *)));
ZEND_MAP_PTR_SET(op_array->run_time_cache, NULL);
}
+
+ zend_init_static_variables_map_ptr(op_array);
}
if (function->common.function_name) {
if (CG(compiler_options) & ZEND_COMPILE_PRELOAD) {
op_array->fn_flags |= ZEND_ACC_PRELOADED;
ZEND_MAP_PTR_NEW(op_array->run_time_cache);
- ZEND_MAP_PTR_NEW(op_array->static_variables_ptr);
} else {
- ZEND_MAP_PTR_INIT(op_array->run_time_cache, zend_arena_alloc(&CG(arena), sizeof(void*)));
+ ZEND_MAP_PTR_INIT(op_array->run_time_cache, zend_arena_alloc(&CG(arena), sizeof(void *)));
ZEND_MAP_PTR_SET(op_array->run_time_cache, NULL);
}
zend_do_extended_stmt();
zend_emit_final_return(0);
+ zend_init_static_variables_map_ptr(op_array);
pass_two(CG(active_op_array));
zend_oparray_context_end(&orig_oparray_context);
void zend_resolve_goto_label(zend_op_array *op_array, zend_op *opline);
ZEND_API void function_add_ref(zend_function *function);
+void zend_init_static_variables_map_ptr(zend_op_array *op_array);
#define INITIAL_OP_ARRAY_SIZE 64
if (op_array->type == ZEND_INTERNAL_FUNCTION) {
break;
}
- if (op_array->static_variables) {
+ if (ZEND_MAP_PTR(op_array->static_variables_ptr)) {
HashTable *ht = ZEND_MAP_PTR_GET(op_array->static_variables_ptr);
if (ht) {
- zend_array_release(ht);
+ zend_array_destroy(ht);
ZEND_MAP_PTR_SET(op_array->static_variables_ptr, NULL);
}
}
zend_op_array *op_array;
ZEND_HASH_FOREACH_PTR(&ce->function_table, op_array) {
if (op_array->type == ZEND_USER_FUNCTION) {
- if (op_array->static_variables) {
+ if (ZEND_MAP_PTR(op_array->static_variables_ptr)) {
HashTable *ht = ZEND_MAP_PTR_GET(op_array->static_variables_ptr);
if (ht) {
- zend_array_release(ht);
+ zend_array_destroy(ht);
ZEND_MAP_PTR_SET(op_array->static_variables_ptr, NULL);
}
}
static zend_function *zend_duplicate_user_function(zend_function *func) /* {{{ */
{
- zend_function *new_function;
-
- new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
- memcpy(new_function, func, sizeof(zend_op_array));
-
- if (CG(compiler_options) & ZEND_COMPILE_PRELOAD) {
- ZEND_ASSERT(new_function->op_array.fn_flags & ZEND_ACC_PRELOADED);
- ZEND_MAP_PTR_NEW(new_function->op_array.static_variables_ptr);
- } else {
- ZEND_MAP_PTR_INIT(new_function->op_array.static_variables_ptr, &new_function->op_array.static_variables);
- }
-
- HashTable *static_properties_ptr = ZEND_MAP_PTR_GET(func->op_array.static_variables_ptr);
- if (static_properties_ptr) {
- /* See: Zend/tests/method_static_var.phpt */
- ZEND_MAP_PTR_SET(new_function->op_array.static_variables_ptr, static_properties_ptr);
- GC_TRY_ADDREF(static_properties_ptr);
- } else {
- GC_TRY_ADDREF(new_function->op_array.static_variables);
- }
-
- return new_function;
+ zend_op_array *new_op_array = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
+ memcpy(new_op_array, func, sizeof(zend_op_array));
+ zend_init_static_variables_map_ptr(new_op_array);
+ return (zend_function *) new_op_array;
}
/* }}} */
for (; p != end; p++) {
zend_op_array *op_array, *new_op_array;
void ***run_time_cache_ptr;
+ size_t alloc_size;
op_array = Z_PTR(p->val);
ZEND_ASSERT(op_array->type == ZEND_USER_FUNCTION);
ZEND_ASSERT(op_array->scope == pce);
ZEND_ASSERT(op_array->prototype == NULL);
- new_op_array = zend_arena_alloc(&CG(arena), sizeof(zend_op_array) + sizeof(void*));
+ alloc_size = sizeof(zend_op_array) + sizeof(void *);
+ if (op_array->static_variables) {
+ alloc_size += sizeof(HashTable *);
+ }
+ new_op_array = zend_arena_alloc(&CG(arena), alloc_size);
Z_PTR(p->val) = new_op_array;
memcpy(new_op_array, op_array, sizeof(zend_op_array));
run_time_cache_ptr = (void***)(new_op_array + 1);
new_op_array->fn_flags &= ~ZEND_ACC_IMMUTABLE;
new_op_array->scope = ce;
ZEND_MAP_PTR_INIT(new_op_array->run_time_cache, run_time_cache_ptr);
- ZEND_MAP_PTR_INIT(new_op_array->static_variables_ptr, &new_op_array->static_variables);
+ if (op_array->static_variables) {
+ HashTable **static_variables_ptr = (HashTable **) (run_time_cache_ptr + 1);
+ *static_variables_ptr = NULL;
+ ZEND_MAP_PTR_INIT(new_op_array->static_variables_ptr, static_variables_ptr);
+ }
zend_update_inherited_handler(constructor);
zend_update_inherited_handler(destructor);
zend_emit_final_return(type == ZEND_USER_FUNCTION);
op_array->line_start = 1;
op_array->line_end = last_lineno;
+ zend_init_static_variables_map_ptr(op_array);
pass_two(op_array);
zend_oparray_context_end(&original_oparray_context);
zend_file_context_end(&original_file_context);
op_array->last_live_range = 0;
op_array->static_variables = NULL;
- ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, &op_array->static_variables);
+ ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, NULL);
op_array->last_try_catch = 0;
op_array->fn_flags = 0;
{
uint32_t i;
- if (op_array->static_variables) {
+ if (ZEND_MAP_PTR(op_array->static_variables_ptr)) {
HashTable *ht = ZEND_MAP_PTR_GET(op_array->static_variables_ptr);
- if (ht && !(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
- if (GC_DELREF(ht) == 0) {
- zend_array_destroy(ht);
- }
+ if (ht) {
+ zend_array_destroy(ht);
}
}
}
efree(arg_info);
}
+ if (op_array->static_variables) {
+ zend_array_destroy(op_array->static_variables);
+ }
}
static void zend_update_extended_stmts(zend_op_array *op_array)
ht = ZEND_MAP_PTR_GET(EX(func)->op_array.static_variables_ptr);
if (!ht) {
- ZEND_ASSERT(EX(func)->op_array.fn_flags & (ZEND_ACC_IMMUTABLE|ZEND_ACC_PRELOADED));
ht = zend_array_dup(EX(func)->op_array.static_variables);
ZEND_MAP_PTR_SET(EX(func)->op_array.static_variables_ptr, ht);
- } else if (GC_REFCOUNT(ht) > 1) {
- if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
- GC_DELREF(ht);
- }
- ht = zend_array_dup(ht);
- ZEND_MAP_PTR_SET(EX(func)->op_array.static_variables_ptr, ht);
}
+ ZEND_ASSERT(GC_REFCOUNT(ht) == 1);
value = (zval*)((char*)ht->arData + (opline->extended_value & ~(ZEND_BIND_REF|ZEND_BIND_IMPLICIT)));
ht = ZEND_MAP_PTR_GET(EX(func)->op_array.static_variables_ptr);
if (!ht) {
- ZEND_ASSERT(EX(func)->op_array.fn_flags & (ZEND_ACC_IMMUTABLE|ZEND_ACC_PRELOADED));
ht = zend_array_dup(EX(func)->op_array.static_variables);
ZEND_MAP_PTR_SET(EX(func)->op_array.static_variables_ptr, ht);
- } else if (GC_REFCOUNT(ht) > 1) {
- if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
- GC_DELREF(ht);
- }
- ht = zend_array_dup(ht);
- ZEND_MAP_PTR_SET(EX(func)->op_array.static_variables_ptr, ht);
}
+ ZEND_ASSERT(GC_REFCOUNT(ht) == 1);
value = (zval*)((char*)ht->arData + (opline->extended_value & ~(ZEND_BIND_REF|ZEND_BIND_IMPLICIT)));
return NULL;
}
-static bool is_array_cacheable(zval *zv)
-{
- zval *p;
-
- ZEND_HASH_FOREACH_VAL(Z_ARR_P(zv), p) {
- if (Z_REFCOUNTED_P(p)) {
- if (Z_TYPE_P(p) == IS_ARRAY) {
- if (!is_array_cacheable(p)) {
- /* Can't cache */
- return 0;
- }
- } else if (Z_TYPE_P(p) == IS_OBJECT || Z_TYPE_P(p) == IS_RESOURCE || Z_TYPE_P(p) == IS_REFERENCE) {
- /* Can't cache */
- return 0;
- }
- }
- } ZEND_HASH_FOREACH_END();
-
- return 1;
-}
-
static zend_class_entry* zend_accel_inheritance_cache_add(zend_class_entry *ce, zend_class_entry *proto, zend_class_entry *parent, zend_class_entry **traits_and_interfaces, HashTable *dependencies)
{
zend_persistent_script dummy;
}
}
- if (ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS) {
- zend_op_array *op_array;
- zval *zv;
-
- ZEND_HASH_FOREACH_PTR(&ce->function_table, op_array) {
- if (op_array->type == ZEND_USER_FUNCTION
- && op_array->static_variables
- && !(GC_FLAGS(op_array->static_variables) & IS_ARRAY_IMMUTABLE)) {
- if (UNEXPECTED(GC_REFCOUNT(op_array->static_variables) > 1)) {
- GC_DELREF(op_array->static_variables);
- op_array->static_variables = zend_array_dup(op_array->static_variables);
- }
- ZEND_HASH_FOREACH_VAL(op_array->static_variables, zv) {
- if (Z_ISREF_P(zv)) {
- zend_reference *ref = Z_REF_P(zv);
-
- ZVAL_COPY_VALUE(zv, &ref->val);
- if (GC_DELREF(ref) == 0) {
- efree_size(ref, sizeof(zend_reference));
- }
- }
- if (Z_REFCOUNTED_P(zv)) {
- if (Z_TYPE_P(zv) == IS_ARRAY) {
- if (!is_array_cacheable(zv)) {
- /* Can't cache */
- return NULL;
- }
- SEPARATE_ARRAY(zv);
- } else if (Z_TYPE_P(zv) == IS_OBJECT || Z_TYPE_P(zv) == IS_RESOURCE) {
- /* Can't cache */
- return NULL;
- }
- }
- } ZEND_HASH_FOREACH_END();
- }
- } ZEND_HASH_FOREACH_END();
- }
-
SHM_UNPROTECT();
zend_shared_alloc_lock();
//??? efree(op_array->refcount);
op_array->refcount = NULL;
- if (op_array->static_variables &&
- !(GC_FLAGS(op_array->static_variables) & IS_ARRAY_IMMUTABLE)) {
- GC_ADDREF(op_array->static_variables);
- }
-
zend_hash_add_ptr(preload_scripts, script->script.filename, script);
}
--EXPECT--
int(1)
int(2)
+int(1)
int(2)
-int(3)
int(1)
int(1)
op_array = (zend_op_array *) emalloc(sizeof(zend_op_array));
*op_array = persistent_script->script.main_op_array;
- ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, &op_array->static_variables);
if (zend_hash_num_elements(&persistent_script->script.function_table) > 0) {
zend_accel_function_hash_copy(CG(function_table), &persistent_script->script.function_table);
if (op_array->static_variables) {
ZEND_MAP_PTR_NEW(op_array->static_variables_ptr);
} else {
- ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, &op_array->static_variables);
+ ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, NULL);
}
ZEND_MAP_PTR_NEW(op_array->run_time_cache);
} else {
op_array->fn_flags &= ~ZEND_ACC_IMMUTABLE;
- ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, &op_array->static_variables);
+ if (op_array->static_variables) {
+ ZEND_MAP_PTR_INIT(op_array->static_variables_ptr,
+ zend_arena_alloc(&CG(arena), sizeof(HashTable *)));
+ ZEND_MAP_PTR_SET(op_array->static_variables_ptr, NULL);
+ }
if (op_array != &script->script.main_op_array) {
ZEND_MAP_PTR_INIT(op_array->run_time_cache, zend_arena_alloc(&CG(arena), sizeof(void*)));
ZEND_MAP_PTR_SET(op_array->run_time_cache, NULL);
if (op_array->static_variables) {
ZEND_MAP_PTR_NEW(op_array->static_variables_ptr);
}
- } else {
- ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, &op_array->static_variables);
}
}
} else {
if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
ZEND_MAP_PTR_INIT(op_array->run_time_cache, NULL);
+ ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, NULL);
}
- ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, &op_array->static_variables);
}
}
zend_persist_op_array_ex(&script->script.main_op_array, script);
if (!script->corrupted) {
ZEND_MAP_PTR_INIT(script->script.main_op_array.run_time_cache, NULL);
+ if (script->script.main_op_array.static_variables) {
+ ZEND_MAP_PTR_NEW(script->script.main_op_array.static_variables_ptr);
+ }
}
- ZEND_MAP_PTR_INIT(script->script.main_op_array.static_variables_ptr,
- &script->script.main_op_array.static_variables);
zend_persist_warnings(script);
if (for_shm) {
array_init(return_value);
ht = ZEND_MAP_PTR_GET(fptr->op_array.static_variables_ptr);
if (!ht) {
- ZEND_ASSERT(fptr->op_array.fn_flags & ZEND_ACC_IMMUTABLE);
ht = zend_array_dup(fptr->op_array.static_variables);
ZEND_MAP_PTR_SET(fptr->op_array.static_variables_ptr, ht);
}