diff options
author | Dmitry Stogov <dmitry@zend.com> | 2014-12-21 03:03:49 +0000 |
---|---|---|
committer | Andrea Faulds <ajf@ajf.me> | 2014-12-21 03:03:49 +0000 |
commit | 0833fd4619978c0522056b44dd53cd3b9d974cdd (patch) | |
tree | 19ad1d216fc70e025d5609ba58ef74e4ed8a1b30 | |
parent | c94f62d0d98f4373bbf8f68c234b16d52c5f3273 (diff) | |
download | php-git-0833fd4619978c0522056b44dd53cd3b9d974cdd.tar.gz |
Allow arrays with define(), to match const syntax support
-rw-r--r-- | NEWS | 1 | ||||
-rw-r--r-- | UPGRADING | 1 | ||||
-rw-r--r-- | Zend/tests/008.phpt | 6 | ||||
-rw-r--r-- | Zend/tests/bug37811.phpt | 2 | ||||
-rw-r--r-- | Zend/tests/constant_arrays.phpt | 99 | ||||
-rw-r--r-- | Zend/tests/constants_002.phpt | 2 | ||||
-rw-r--r-- | Zend/zend_builtin_functions.c | 78 |
7 files changed, 182 insertions, 7 deletions
@@ -31,6 +31,7 @@ . Fixed bug #55415 (php_info produces invalid anchor names). (Kalle, Johannes) . Added ?? operator. (Andrea) . Added \u{xxxxx} Unicode Codepoint Escape Syntax. (Andrea) + . Fixed oversight where define() did not support arrays yet const syntax did. (Andrea, Dmitry) - Date: . Fixed day_of_week function as it could sometimes return negative values @@ -72,6 +72,7 @@ PHP X.Y UPGRADE NOTES . Closure::call() method added . Added \u{xxxxxx} Unicode Codepoint Escape Syntax for double-quoted strings and heredocs. + . define() now supports arrays as constant values, fixing an oversight where define() did not support arrays yet const syntax did. (Andrea, Dmitry) - Standard . intdiv() function for integer division added. diff --git a/Zend/tests/008.phpt b/Zend/tests/008.phpt index 4f58e80b00..3e990fb768 100644 --- a/Zend/tests/008.phpt +++ b/Zend/tests/008.phpt @@ -41,11 +41,9 @@ bool(true) Notice: Constant test const already defined in %s on line %d bool(false) +bool(true) -Warning: Constants may only evaluate to scalar values in %s on line %d -bool(false) - -Warning: Constants may only evaluate to scalar values in %s on line %d +Warning: Constants may only evaluate to scalar values or arrays in %s on line %d bool(false) int(1) int(2) diff --git a/Zend/tests/bug37811.phpt b/Zend/tests/bug37811.phpt index 70c4c90ede..f224f9b311 100644 --- a/Zend/tests/bug37811.phpt +++ b/Zend/tests/bug37811.phpt @@ -21,7 +21,7 @@ var_dump(Baz); --EXPECTF-- string(3) "Foo" -Warning: Constants may only evaluate to scalar values in %sbug37811.php on line %d +Warning: Constants may only evaluate to scalar values or arrays in %sbug37811.php on line %d Notice: Use of undefined constant Baz - assumed 'Baz' in %sbug37811.php on line %d string(3) "Baz" diff --git a/Zend/tests/constant_arrays.phpt b/Zend/tests/constant_arrays.phpt new file mode 100644 index 0000000000..834c12606e --- /dev/null +++ b/Zend/tests/constant_arrays.phpt @@ -0,0 +1,99 @@ +--TEST-- +Constant arrays +--FILE-- +<?php + +define('FOOBAR', [1, 2, 3, ['foo' => 'bar']]); +const FOO_BAR = [1, 2, 3, ['foo' => 'bar']]; + +$x = FOOBAR; +$x[0] = 7; +var_dump($x, FOOBAR); + +$x = FOO_BAR; +$x[0] = 7; +var_dump($x, FOO_BAR); + +// ensure references are removed +$x = 7; +$y = [&$x]; +define('QUX', $y); +$y[0] = 3; +var_dump($x, $y, QUX); + +// ensure objects not allowed in arrays +var_dump(define('ELEPHPANT', [new StdClass])); + +// ensure recursion doesn't crash +$recursive = []; +$recursive[0] = &$recursive; +var_dump(define('RECURSION', $recursive)); + +--EXPECTF-- +array(4) { + [0]=> + int(7) + [1]=> + int(2) + [2]=> + int(3) + [3]=> + array(1) { + ["foo"]=> + string(3) "bar" + } +} +array(4) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + [3]=> + array(1) { + ["foo"]=> + string(3) "bar" + } +} +array(4) { + [0]=> + int(7) + [1]=> + int(2) + [2]=> + int(3) + [3]=> + array(1) { + ["foo"]=> + string(3) "bar" + } +} +array(4) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + [3]=> + array(1) { + ["foo"]=> + string(3) "bar" + } +} +int(3) +array(1) { + [0]=> + int(3) +} +array(1) { + [0]=> + int(7) +} + +Warning: Constants may only evaluate to scalar values or arrays in %s on line %d +bool(false) + +Warning: Constants cannot be recursive arrays in %s on line %d +bool(false) diff --git a/Zend/tests/constants_002.phpt b/Zend/tests/constants_002.phpt index 5acca981ff..d590bf44b9 100644 --- a/Zend/tests/constants_002.phpt +++ b/Zend/tests/constants_002.phpt @@ -11,7 +11,7 @@ var_dump(foo); ?> --EXPECTF-- -Warning: Constants may only evaluate to scalar values in %s on line %d +Warning: Constants may only evaluate to scalar values or arrays in %s on line %d Notice: Use of undefined constant foo - assumed 'foo' in %s on line %d string(%d) "foo" diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index c05e797013..f956f492b4 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -688,6 +688,71 @@ ZEND_FUNCTION(error_reporting) } /* }}} */ +static int validate_constant_array(HashTable *ht) /* {{{ */ +{ + int ret = 1; + zval *val; + + ht->u.v.nApplyCount++; + ZEND_HASH_FOREACH_VAL_IND(ht, val) { + ZVAL_DEREF(val); + if (Z_REFCOUNTED_P(val)) { + if (Z_TYPE_P(val) == IS_ARRAY) { + if (!Z_IMMUTABLE_P(val)) { + if (Z_ARRVAL_P(val)->u.v.nApplyCount > 0) { + zend_error(E_WARNING, "Constants cannot be recursive arrays"); + ret = 0; + break; + } else if (!validate_constant_array(Z_ARRVAL_P(val))) { + ret = 0; + break; + } + } + } else if (Z_TYPE_P(val) != IS_STRING && Z_TYPE_P(val) != IS_RESOURCE) { + zend_error(E_WARNING, "Constants may only evaluate to scalar values or arrays"); + ret = 0; + break; + } + } + } ZEND_HASH_FOREACH_END(); + ht->u.v.nApplyCount--; + return ret; +} +/* }}} */ + +static void copy_constant_array(zval *dst, zval *src) /* {{{ */ +{ + zend_string *key; + zend_ulong idx; + zval *new_val, *val; + + array_init_size(dst, zend_hash_num_elements(Z_ARRVAL_P(src))); + ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(src), idx, key, val) { + /* constant arrays can't contain references */ + if (Z_ISREF_P(val)) { + if (Z_REFCOUNT_P(val) == 1) { + ZVAL_UNREF(val); + } else { + Z_DELREF_P(val); + val = Z_REFVAL_P(val); + } + } + if (key) { + new_val = zend_hash_add_new(Z_ARRVAL_P(dst), key, val); + } else { + new_val = zend_hash_index_add_new(Z_ARRVAL_P(dst), idx, val); + } + if (Z_TYPE_P(val) == IS_ARRAY) { + if (!Z_IMMUTABLE_P(val)) { + copy_constant_array(new_val, val); + } + } else if (Z_REFCOUNTED_P(val)) { + Z_ADDREF_P(val); + } + } ZEND_HASH_FOREACH_END(); +} +/* }}} */ + /* {{{ proto bool define(string constant_name, mixed value, boolean case_insensitive=false) Define a new constant */ ZEND_FUNCTION(define) @@ -733,6 +798,16 @@ repeat: case IS_RESOURCE: case IS_NULL: break; + case IS_ARRAY: + if (!Z_IMMUTABLE_P(val)) { + if (!validate_constant_array(Z_ARRVAL_P(val))) { + RETURN_FALSE; + } else { + copy_constant_array(&c.value, val); + goto register_constant; + } + } + break; case IS_OBJECT: if (Z_TYPE(val_free) == IS_UNDEF) { if (Z_OBJ_HT_P(val)->get) { @@ -749,13 +824,14 @@ repeat: } /* no break */ default: - zend_error(E_WARNING,"Constants may only evaluate to scalar values"); + zend_error(E_WARNING, "Constants may only evaluate to scalar values or arrays"); zval_ptr_dtor(&val_free); RETURN_FALSE; } ZVAL_DUP(&c.value, val); zval_ptr_dtor(&val_free); +register_constant: c.flags = case_sensitive; /* non persistent */ c.name = zend_string_copy(name); c.module_number = PHP_USER_CONSTANT; |