From fc99e89baf6589409fb8618ea91880b916d9b390 Mon Sep 17 00:00:00 2001 From: Gabriel Caruso Date: Sat, 2 Nov 2019 16:29:42 +0100 Subject: [PATCH 1/3] Fix slowest tests --- .../tests/file/005_variation-win32.phpt | 51 +++++++++++++------ .../tests/file/lstat_stat_variation10.phpt | 2 +- .../tests/file/lstat_stat_variation11.phpt | 2 +- .../tests/file/lstat_stat_variation12.phpt | 2 +- .../tests/file/lstat_stat_variation13.phpt | 2 +- .../tests/file/lstat_stat_variation16.phpt | 2 +- .../tests/file/lstat_stat_variation17.phpt | 2 +- .../tests/file/lstat_stat_variation21.phpt | 2 +- .../tests/file/lstat_stat_variation4.phpt | 2 +- .../tests/file/lstat_stat_variation5.phpt | 2 +- .../tests/file/lstat_stat_variation8.phpt | 2 +- .../tests/file/stat_basic-win32-mb.phpt | 4 +- ext/standard/tests/file/stat_basic-win32.phpt | 2 +- .../tests/file/stat_variation1-win32-mb.phpt | 2 +- .../tests/file/stat_variation1-win32.phpt | 2 +- .../tests/file/stat_variation2-win32.phpt | 2 +- .../tests/file/stat_variation3-win32.phpt | 2 +- .../tests/file/stat_variation4-win32.phpt | 2 +- .../tests/file/stat_variation5-win32.phpt | 2 +- .../tests/file/stat_variation6-win32.phpt | 5 +- .../tests/file/stat_variation8-win32.phpt | 2 +- 21 files changed, 59 insertions(+), 37 deletions(-) diff --git a/ext/standard/tests/file/005_variation-win32.phpt b/ext/standard/tests/file/005_variation-win32.phpt index 1e712b7828c6b..42502b65094d4 100644 --- a/ext/standard/tests/file/005_variation-win32.phpt +++ b/ext/standard/tests/file/005_variation-win32.phpt @@ -40,7 +40,6 @@ function stat_fn( $filename ) { echo "-- inode change time is => "; print( @date( 'Y:M:D:H:i:s', filectime($filename) ) )."\n"; clearstatcache(); - } echo "*** Testing fileattime(), filemtime(), filectime() & touch() : usage variations ***\n"; @@ -49,12 +48,12 @@ $file_path = __DIR__; $file_handle = fopen("$file_path/005_variation1.tmp", "w"); fclose($file_handle); stat_fn("$file_path/005_variation1.tmp"); -sleep(2); +sleep(1); $file_handle = fopen("$file_path/005_variation2.tmp", "w"); fclose($file_handle); stat_fn("$file_path/005_variation2.tmp"); -sleep(2); +sleep(1); $file_handle = fopen("$file_path/005_variation3.tmp", "w"); fclose($file_handle); @@ -70,13 +69,13 @@ $file_name = "$file_path/005_variation1.tmp"; $file_write_handle = fopen($file_name, "w"); fclose($file_write_handle); stat_fn($file_name); -sleep(2); +sleep(1); /* filectime + 2 */ echo "\n-- Checking different times, after changing the file permission --\n"; chmod($file_name, 0777); stat_fn($file_name); -sleep(2); +sleep(1); /* filemtime + 2 & filectime + 2 */ echo "\n-- Checking different times, after writing into the file --\n"; @@ -84,7 +83,7 @@ $file_write_handle = fopen($file_name, "w"); fwrite($file_write_handle, "Hello, world"); fclose($file_write_handle); stat_fn($file_name); -sleep(2); +sleep(1); /* fileatime + 2 */ echo "\n-- Checking different times, after reading from the file --\n"; @@ -92,42 +91,54 @@ $file_read_handle = fopen($file_name ,"r"); fread($file_read_handle, 10); fclose( $file_read_handle); stat_fn($file_name); -sleep(2); +sleep(1); + +/* No change */ +echo "\n-- Checking same times, after creating a softlink to the file --\n"; +symlink($file_name, "$file_path/005_variation_softlink.tmp"); +stat_fn($file_name); +sleep(1); + +/* filectime + 2 */ +echo "\n-- Checking different times, after creating a hardlink to the file --\n"; +link($file_name, "$file_path/005_variation_hardlink.tmp"); +stat_fn($file_name); +sleep(1); /* No change */ -echo "\n-- Checking different times, after making a copy of the file --\n"; +echo "\n-- Checking same times, after making a copy of the file --\n"; $file_copy = "$file_path/005_variation_copy.tmp"; copy($file_name, $file_copy); stat_fn($file_name); -sleep(2); +sleep(1); /* fileatime + 2 */ echo "\n-- Checking different times, after performing is_file() operation on the file --\n"; is_file($file_name); stat_fn($file_name); -sleep(2); +sleep(1); echo "\n*** Testing touch() function with different time values ***\n"; $file_name2 = $file_path."/005_variation_touch.tmp"; $file_handle = fopen($file_name2, "w"); fclose($file_handle); -sleep(2); +sleep(1); /* Time is not mentioned */ var_dump( touch($file_name2) ); //set to current system time stat_fn($file_name2); -sleep(2); +sleep(1); /* set to access(creation time of the file) time */ var_dump( touch($file_name2, @date(fileatime($file_name2))) ); stat_fn($file_name2); -sleep(2); +sleep(1); /* set to access time of $file_name2 */ var_dump( touch($file_path."/005_variation_touch_fly.tmp", @date(fileatime($file_name2)), time()) ); stat_fn($file_name2); -sleep(2); +sleep(1); /* set to default value, with Invalid timestamps */ var_dump( touch($file_name2, 10) ); @@ -184,7 +195,17 @@ unlink($file_path."/005_variation_touch_new.tmp"); -- File modification time is => %d:%s:%s:%d:%d:%d -- inode change time is => %d:%s:%s:%d:%d:%d --- Checking different times, after making a copy of the file -- +-- Checking same times, after creating a softlink to the file -- +-- File access time is => %d:%s:%s:%d:%d:%d +-- File modification time is => %d:%s:%s:%d:%d:%d +-- inode change time is => %d:%s:%s:%d:%d:%d + +-- Checking different times, after creating a hardlink to the file -- +-- File access time is => %d:%s:%s:%d:%d:%d +-- File modification time is => %d:%s:%s:%d:%d:%d +-- inode change time is => %d:%s:%s:%d:%d:%d + +-- Checking same times, after making a copy of the file -- -- File access time is => %d:%s:%s:%d:%d:%d -- File modification time is => %d:%s:%s:%d:%d:%d -- inode change time is => %d:%s:%s:%d:%d:%d diff --git a/ext/standard/tests/file/lstat_stat_variation10.phpt b/ext/standard/tests/file/lstat_stat_variation10.phpt index 16ff75c26da8a..30578f5d184d1 100644 --- a/ext/standard/tests/file/lstat_stat_variation10.phpt +++ b/ext/standard/tests/file/lstat_stat_variation10.phpt @@ -31,7 +31,7 @@ echo "*** Testing stat() on directory after using is_dir() on it ***\n"; $old_stat = stat($dirname); // clear the cache clearstatcache(); -sleep(2); +sleep(1); var_dump( is_dir($dirname) ); $new_stat = stat($dirname); diff --git a/ext/standard/tests/file/lstat_stat_variation11.phpt b/ext/standard/tests/file/lstat_stat_variation11.phpt index 9a394ae7e9a8d..523bfacf5c8f4 100644 --- a/ext/standard/tests/file/lstat_stat_variation11.phpt +++ b/ext/standard/tests/file/lstat_stat_variation11.phpt @@ -31,7 +31,7 @@ echo "*** Testing stat() on a file after using is_file() on it ***\n"; $old_stat = stat($filename); // clear the stat clearstatcache(); -sleep(2); +sleep(1); var_dump( is_file($filename) ); $new_stat = stat($filename); // compare self stats diff --git a/ext/standard/tests/file/lstat_stat_variation12.phpt b/ext/standard/tests/file/lstat_stat_variation12.phpt index eada799cdf99b..15f081f21f45a 100644 --- a/ext/standard/tests/file/lstat_stat_variation12.phpt +++ b/ext/standard/tests/file/lstat_stat_variation12.phpt @@ -36,7 +36,7 @@ $linkname = "$file_path/lstat_stat_variation12_link.tmp"; $old_stat = lstat($linkname); // clear the stat clearstatcache(); -sleep(2); +sleep(1); var_dump( is_link($linkname) ); $new_stat = lstat($linkname); // compare self stats diff --git a/ext/standard/tests/file/lstat_stat_variation13.phpt b/ext/standard/tests/file/lstat_stat_variation13.phpt index 22694240f57db..e94a5085ec3a9 100644 --- a/ext/standard/tests/file/lstat_stat_variation13.phpt +++ b/ext/standard/tests/file/lstat_stat_variation13.phpt @@ -30,7 +30,7 @@ fclose($file_handle); $old_stat = stat($filename); // clear the stat clearstatcache(); -sleep(2); +sleep(1); // opening file again in read mode $file_handle = fopen($filename, "r"); // read file fclose($file_handle); diff --git a/ext/standard/tests/file/lstat_stat_variation16.phpt b/ext/standard/tests/file/lstat_stat_variation16.phpt index 652f5c29c7bd3..93791355bab1e 100644 --- a/ext/standard/tests/file/lstat_stat_variation16.phpt +++ b/ext/standard/tests/file/lstat_stat_variation16.phpt @@ -28,7 +28,7 @@ fclose($fp); // checking stat() on file after changing its permission echo "*** Testing lstat() on a file after changing its access permission ***\n"; $old_stat = stat($filename); -sleep(2); +sleep(1); var_dump( chmod($filename, 0777) ); // clear the stat clearstatcache(); diff --git a/ext/standard/tests/file/lstat_stat_variation17.phpt b/ext/standard/tests/file/lstat_stat_variation17.phpt index 208cc0b388ac2..64039566f0b58 100644 --- a/ext/standard/tests/file/lstat_stat_variation17.phpt +++ b/ext/standard/tests/file/lstat_stat_variation17.phpt @@ -27,7 +27,7 @@ $dirname = "$file_path/lstat_stat_variation17"; mkdir($dirname); $old_stat = stat($dirname); -sleep(2); +sleep(1); var_dump( chmod($dirname, 0777) ); // clear the stat clearstatcache(); diff --git a/ext/standard/tests/file/lstat_stat_variation21.phpt b/ext/standard/tests/file/lstat_stat_variation21.phpt index 23ed53e566861..df09bc7f98b93 100644 --- a/ext/standard/tests/file/lstat_stat_variation21.phpt +++ b/ext/standard/tests/file/lstat_stat_variation21.phpt @@ -33,7 +33,7 @@ echo "*** Testing stat() on file by truncating it to given size ***\n"; $old_stat = stat($filename); // clear the cache clearstatcache(); -sleep(2); +sleep(1); // opening file in r/w mode $file_handle = fopen($filename, "r+"); var_dump( ftruncate($file_handle, 512) ); // truncate it diff --git a/ext/standard/tests/file/lstat_stat_variation4.phpt b/ext/standard/tests/file/lstat_stat_variation4.phpt index fe8b61e5ca2fa..c72d7ffe4bdb2 100644 --- a/ext/standard/tests/file/lstat_stat_variation4.phpt +++ b/ext/standard/tests/file/lstat_stat_variation4.phpt @@ -33,7 +33,7 @@ echo "*** Testing stat() for file after using touch() on the file ***\n"; $old_stat = stat($file_name); // clear the cache clearstatcache(); -sleep(2); +sleep(1); var_dump( touch($file_name) ); $new_stat = stat($file_name); diff --git a/ext/standard/tests/file/lstat_stat_variation5.phpt b/ext/standard/tests/file/lstat_stat_variation5.phpt index b5c03c3f08f87..668e79238d2ab 100644 --- a/ext/standard/tests/file/lstat_stat_variation5.phpt +++ b/ext/standard/tests/file/lstat_stat_variation5.phpt @@ -33,7 +33,7 @@ echo "*** Testing stat() for directory after using touch() on the directory ***\ $old_stat = stat($dir_name); // clear the cache clearstatcache(); -sleep(2); +sleep(1); var_dump( touch($dir_name) ); $new_stat = stat($dir_name); diff --git a/ext/standard/tests/file/lstat_stat_variation8.phpt b/ext/standard/tests/file/lstat_stat_variation8.phpt index db7f87f7f7968..9870a56c10a1c 100644 --- a/ext/standard/tests/file/lstat_stat_variation8.phpt +++ b/ext/standard/tests/file/lstat_stat_variation8.phpt @@ -30,7 +30,7 @@ echo "*** Testing stat() on dir after subdir and file is created in it ***\n"; $dirname = "$file_path/lstat_stat_variation8"; $old_stat = stat($dirname); clearstatcache(); -sleep(2); +sleep(1); mkdir("$dirname/lstat_stat_variation8_subdir"); $file_handle = fopen("$dirname/lstat_stat_variation8a.tmp", "w"); fclose($file_handle); diff --git a/ext/standard/tests/file/stat_basic-win32-mb.phpt b/ext/standard/tests/file/stat_basic-win32-mb.phpt index 504e0f45eab16..29f1514d769aa 100644 --- a/ext/standard/tests/file/stat_basic-win32-mb.phpt +++ b/ext/standard/tests/file/stat_basic-win32-mb.phpt @@ -26,7 +26,7 @@ mkdir($dirname); // stat of the dir created $dir_stat = stat($dirname); clearstatcache(); -sleep(2); +sleep(1); // creating file $filename = "$dirname/stat_basic_私はガラスを食べられます.tmp"; @@ -34,7 +34,7 @@ $file_handle = fopen($filename, "w"); fclose($file_handle); // stat of the file created $file_stat = stat($filename); -sleep(2); +sleep(1); // now new stat of the dir after file is created $new_dir_stat = stat($dirname); diff --git a/ext/standard/tests/file/stat_basic-win32.phpt b/ext/standard/tests/file/stat_basic-win32.phpt index 348ac2d38095d..4df0064688914 100644 --- a/ext/standard/tests/file/stat_basic-win32.phpt +++ b/ext/standard/tests/file/stat_basic-win32.phpt @@ -34,7 +34,7 @@ $file_handle = fopen($filename, "w"); fclose($file_handle); // stat of the file created $file_stat = stat($filename); -sleep(2); +sleep(1); // now new stat of the dir after file is created $new_dir_stat = stat($dirname); diff --git a/ext/standard/tests/file/stat_variation1-win32-mb.phpt b/ext/standard/tests/file/stat_variation1-win32-mb.phpt index 1db467632b046..002d5ac650214 100644 --- a/ext/standard/tests/file/stat_variation1-win32-mb.phpt +++ b/ext/standard/tests/file/stat_variation1-win32-mb.phpt @@ -35,7 +35,7 @@ $old_filename = "$file_path/stat_variation1_私はガラスを食べられます $new_filename = "$file_path/stat_variation1a_私はガラスを食べられます.tmp"; $old_stat = stat($old_filename); clearstatcache(); -sleep(2); +sleep(1); var_dump( rename($old_filename, $new_filename) ); $new_stat = stat($new_filename); diff --git a/ext/standard/tests/file/stat_variation1-win32.phpt b/ext/standard/tests/file/stat_variation1-win32.phpt index 26b1549e02a2d..03d94b8898e2b 100644 --- a/ext/standard/tests/file/stat_variation1-win32.phpt +++ b/ext/standard/tests/file/stat_variation1-win32.phpt @@ -35,7 +35,7 @@ $old_filename = "$file_path/stat_variation1.tmp"; $new_filename = "$file_path/stat_variation1a.tmp"; $old_stat = stat($old_filename); clearstatcache(); -sleep(2); +sleep(1); var_dump( rename($old_filename, $new_filename) ); $new_stat = stat($new_filename); diff --git a/ext/standard/tests/file/stat_variation2-win32.phpt b/ext/standard/tests/file/stat_variation2-win32.phpt index 2d4f44bf02599..66347ce2b541e 100644 --- a/ext/standard/tests/file/stat_variation2-win32.phpt +++ b/ext/standard/tests/file/stat_variation2-win32.phpt @@ -32,7 +32,7 @@ echo "*** Testing stat(): writing to a file ***\n"; echo "-- Testing stat() on file after data is written in it --\n"; $old_stat = stat($filename); clearstatcache(); -sleep(2); +sleep(1); $file_handle = fopen($filename, "w"); // temp file fwrite($file_handle, "Hello World"); fclose($file_handle); diff --git a/ext/standard/tests/file/stat_variation3-win32.phpt b/ext/standard/tests/file/stat_variation3-win32.phpt index d08612fc7f0df..980fc56836db1 100644 --- a/ext/standard/tests/file/stat_variation3-win32.phpt +++ b/ext/standard/tests/file/stat_variation3-win32.phpt @@ -30,7 +30,7 @@ echo "-- Testing stat() on dir after subdir and file is created in it --\n"; $dirname = "$file_path/stat_variation3"; $old_stat = stat($dirname); clearstatcache(); -sleep(2); +sleep(1); mkdir("$dirname/stat_variation3_subdir"); $file_handle = fopen("$dirname/stat_variation3a.tmp", "w"); fclose($file_handle); diff --git a/ext/standard/tests/file/stat_variation4-win32.phpt b/ext/standard/tests/file/stat_variation4-win32.phpt index a5e25f99d03a4..9cae39a4980f2 100644 --- a/ext/standard/tests/file/stat_variation4-win32.phpt +++ b/ext/standard/tests/file/stat_variation4-win32.phpt @@ -36,7 +36,7 @@ $old_dirname = "$file_path/stat_variation4"; $old_stat = stat($old_dirname); // clear the cache clearstatcache(); -sleep(2); +sleep(1); var_dump( is_dir($old_dirname) ); $new_stat = stat($old_dirname); diff --git a/ext/standard/tests/file/stat_variation5-win32.phpt b/ext/standard/tests/file/stat_variation5-win32.phpt index d2c9fd4c84225..47627671dbd45 100644 --- a/ext/standard/tests/file/stat_variation5-win32.phpt +++ b/ext/standard/tests/file/stat_variation5-win32.phpt @@ -32,7 +32,7 @@ fclose($file_handle); $old_stat = stat($filename); // clear the stat clearstatcache(); -sleep(2); +sleep(1); // opening file again in read mode $file_handle = fopen($filename, "r"); // read file fclose($file_handle); diff --git a/ext/standard/tests/file/stat_variation6-win32.phpt b/ext/standard/tests/file/stat_variation6-win32.phpt index 953d7df04581e..3dc7a4bac101a 100644 --- a/ext/standard/tests/file/stat_variation6-win32.phpt +++ b/ext/standard/tests/file/stat_variation6-win32.phpt @@ -32,11 +32,12 @@ fclose($file_handle); // checking stat() on file echo "\n*** Testing stat() on file with miscellaneous file permission and content ***\n"; +clearstatcache(); $old_stat = stat($filename); +sleep(1); var_dump( chmod($filename, 0777) ); // clear the stat clearstatcache(); -sleep(2); $new_stat = stat($filename); // compare self stats var_dump( compare_self_stat($old_stat) ); @@ -50,10 +51,10 @@ clearstatcache(); // clear statement cache // checking stat() on directory echo "\n*** Testing stat() on directory with miscellaneous file permission ***\n"; $old_stat = stat($dirname); +sleep(1); var_dump( chmod($dirname, 0777) ); // clear the stat clearstatcache(); -sleep(2); $new_stat = stat($dirname); // compare self stats var_dump( compare_self_stat($old_stat) ); diff --git a/ext/standard/tests/file/stat_variation8-win32.phpt b/ext/standard/tests/file/stat_variation8-win32.phpt index 7a0cf65d411d7..c86ba3206e149 100644 --- a/ext/standard/tests/file/stat_variation8-win32.phpt +++ b/ext/standard/tests/file/stat_variation8-win32.phpt @@ -37,7 +37,7 @@ fclose($file_handle); clearstatcache(true, $filename); $old_stat = stat($filename); // clear the cache -sleep(2); +sleep(1); // opening file in r/w mode $file_handle = fopen($filename, "r+"); From ade217d05c81eb8fef75d786652cf59e8fd3d1c4 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Sun, 5 Jan 2020 20:08:39 +0100 Subject: [PATCH 2/3] Remove duplicate test cases These had originally used other exit codes as mail_basic5.phpt, but that was changed later with commit d1b12c9[1]. [1] --- ext/standard/tests/mail/mail_basic3.phpt | 33 ----------------------- ext/standard/tests/mail/mail_basic4.phpt | 34 ------------------------ 2 files changed, 67 deletions(-) delete mode 100644 ext/standard/tests/mail/mail_basic3.phpt delete mode 100644 ext/standard/tests/mail/mail_basic4.phpt diff --git a/ext/standard/tests/mail/mail_basic3.phpt b/ext/standard/tests/mail/mail_basic3.phpt deleted file mode 100644 index 57aacfa8656f0..0000000000000 --- a/ext/standard/tests/mail/mail_basic3.phpt +++ /dev/null @@ -1,33 +0,0 @@ ---TEST-- -Test mail() function : basic functionality ---INI-- -sendmail_path="exit 1" ---SKIPIF-- - ---FILE-- - ---EXPECT-- -*** Testing mail() : basic functionality *** --- failure -- -bool(false) diff --git a/ext/standard/tests/mail/mail_basic4.phpt b/ext/standard/tests/mail/mail_basic4.phpt deleted file mode 100644 index 9424ad0400f20..0000000000000 --- a/ext/standard/tests/mail/mail_basic4.phpt +++ /dev/null @@ -1,34 +0,0 @@ ---TEST-- -Test mail() function : basic functionality ---INI-- -sendmail_path="exit 1" ---SKIPIF-- - ---FILE-- - ---EXPECT-- -*** Testing mail() : basic functionality *** --- failure -- -bool(false) From d948924f00fb66d32395b1626bc2fd659df7e579 Mon Sep 17 00:00:00 2001 From: Tyson Andre Date: Sat, 4 Jan 2020 17:37:34 -0500 Subject: [PATCH 3/3] Support 'static const CONST_NAME = dynamic_expr;' Currently, this is limited to the global scope. This can be thought of as similar to C: the static const can only be seen within the namespace block scope. Differences from global constants: - A name can only be declared once per namespace block. - The name can only be used by the following statements in the namespace block. - This can support any expression define() would accept (function calls, $variable, properties, etc.). - This is eagerly evaluated when the expression might be dynamic. This is deliberate, and meant to make accidental infinite recursion (and unexpected side effects of fetching a constant for the first time) less likely. This may throw in the future. - The value from the first successful declaration is used and permanently stored. Similarities to global constants: - 'static const' rejects the same types (references, objects, and reference cycles.) - 'static const' cannot be modified once declared The current implementation allows code such as this: ```php static const LOCAL_X = "Local $x"; class Example { const X = LOCAL_X; } ``` Which is shorthand for: ``` if (!defined('UNIQUE_NAME_FOR_LOCAL_X')) { define('UNIQUE_NAME_FOR_LOCAL_X', "Local $x"); } class Example { const X = \LOCAL_NAME_FOR_LOCAL_X; } ``` Unfinished work: - Work out what to do if the expression throws an exception/error. (Fatal error? Leave as is?) - Decide what this should do if the `define()` call fails. (Fatal error? Throw a regular Error?) - (Optional) opcache optimizations such as evaluating functions at compile time. --- Zend/tests/static_const.phpt | 36 ++++++ Zend/tests/static_const_is_const.phpt | 20 +++ Zend/tests/static_const_not_repeatable.phpt | 11 ++ Zend/tests/static_const_only_top_level.phpt | 11 ++ Zend/zend_ast.c | 1 + Zend/zend_ast.h | 1 + Zend/zend_compile.c | 132 ++++++++++++++++++++ Zend/zend_compile.h | 1 + Zend/zend_language_parser.y | 8 +- 9 files changed, 220 insertions(+), 1 deletion(-) create mode 100644 Zend/tests/static_const.phpt create mode 100644 Zend/tests/static_const_is_const.phpt create mode 100644 Zend/tests/static_const_not_repeatable.phpt create mode 100644 Zend/tests/static_const_only_top_level.phpt diff --git a/Zend/tests/static_const.phpt b/Zend/tests/static_const.phpt new file mode 100644 index 0000000000000..f74a0000bdf4b --- /dev/null +++ b/Zend/tests/static_const.phpt @@ -0,0 +1,36 @@ +--TEST-- +static const supports dynamic expressions +--FILE-- +getMessage() . "\n"; +} +var_dump(VAL1); +--EXPECT-- +Caught: Cannot pass parameter 3 by reference +array(1) { + [0]=> + string(7) "Example" +} diff --git a/Zend/tests/static_const_not_repeatable.phpt b/Zend/tests/static_const_not_repeatable.phpt new file mode 100644 index 0000000000000..7e16d9ba78fe7 --- /dev/null +++ b/Zend/tests/static_const_not_repeatable.phpt @@ -0,0 +1,11 @@ +--TEST-- +static const cannot be repeated in the same namespace block +--FILE-- +child[0]; + zend_ast *value_ast = const_ast->child[1]; + zend_string *unqualified_name = zend_ast_get_str(name_ast); + + zend_string *name; + if (zend_get_special_const(ZSTR_VAL(unqualified_name), ZSTR_LEN(unqualified_name))) { + zend_error_noreturn(E_COMPILE_ERROR, + "Cannot redeclare static constant '%s'", ZSTR_VAL(unqualified_name)); + } + + // "static const" lasts for the life of a namespace block. + name = zend_prefix_with_file(unqualified_name); + name = zend_new_interned_string(name); + + if (!zend_hash_add_ptr(zend_get_import_ht(ZEND_SYMBOL_CONST), unqualified_name, name)) { + zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare static const %s because " + "the name is already in use", ZSTR_VAL(unqualified_name)); + } + zend_eval_const_expr(&value_ast); + + /* 0. Check if it can be evaluated at compile time. */ + if (value_ast->kind != ZEND_AST_ZVAL) { + /* + * This is a dynamic expression, and could not be evaluated with the information available while compiling the file. + * 1. JMPNZ if defined('UNIQUE_CONST_NAME') + * 2. Call define('UNIQUE_CONST_NAME', $dynamicValue) + * 3. update target of JMPNZ + */ + uint32_t opnum_jmpz; + znode defined_opline_result; + zend_op *defined_opline; + // TODO: Skip emitting the DEFINED and just emit DECLARE_CONST directly + // if this can be determined at compile time. + defined_opline = zend_emit_op_tmp(&defined_opline_result, ZEND_DEFINED, NULL, NULL); + defined_opline->op1_type = IS_CONST; + LITERAL_STR(defined_opline->op1, name); + defined_opline->extended_value = zend_alloc_cache_slot(); + + opnum_jmpz = zend_emit_cond_jump(ZEND_JMPNZ, &defined_opline_result, 0); + + { + /* Generate the AST for a call to define('GLOBAL_UNIQUE_CONST', $dynamic) and compile it. */ + zend_ast *define_name_ast; + zend_ast *define_call_ast; + zend_ast *args_ast; + zend_string *define_str = zend_new_interned_string(zend_string_init("define", 6, 0)); + + define_name_ast = zend_ast_create_zval_from_str(define_str); + define_name_ast->attr = ZEND_NAME_FQ; + args_ast = zend_ast_create_list(2, ZEND_AST_ARG_LIST, zend_ast_create_zval_from_str(name), value_ast); + define_call_ast = zend_ast_create(ZEND_AST_CALL, define_name_ast, args_ast); + + zend_compile_expr(NULL, define_call_ast); + /* Temporary ASTs get freed when the arena is freed */ + } + zend_update_jump_target_to_next(opnum_jmpz); + } else { + /* This expression can be evaluated at compile time */ + znode name_node, value_node; + zval *value_zv = &value_node.u.constant; + + value_node.op_type = IS_CONST; + + zend_const_expr_to_zval(value_zv, value_ast); + zend_string_addref(name); + + name_node.op_type = IS_CONST; + ZVAL_STR(&name_node.u.constant, name); + + zend_emit_op(NULL, ZEND_DECLARE_CONST, &name_node, &value_node); + } + + zend_register_seen_symbol(name, ZEND_SYMBOL_CONST); +} +/* }}} */ + +void zend_compile_static_const_decl(zend_ast *ast) /* {{{ */ +{ + zend_ast_list *list = zend_ast_get_list(ast); + uint32_t i; + for (i = 0; i < list->children; ++i) { + zend_compile_static_const_elem(list->child[i]); + } +} +/* }}}*/ + void zend_compile_namespace(zend_ast *ast) /* {{{ */ { zend_ast *name_ast = ast->child[0]; @@ -7011,6 +7139,7 @@ void zend_compile_namespace(zend_ast *ast) /* {{{ */ if (with_bracket) { FC(has_bracketed_namespaces) = 1; } + FC(namespace_id)++; if (stmt_ast) { zend_compile_top_stmt(stmt_ast); @@ -8706,6 +8835,9 @@ void zend_compile_stmt(zend_ast *ast) /* {{{ */ case ZEND_AST_CONST_DECL: zend_compile_const_decl(ast); break; + case ZEND_AST_STATIC_CONST_DECL: + zend_compile_static_const_decl(ast); + break; case ZEND_AST_NAMESPACE: zend_compile_namespace(ast); break; diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index a87204d26753b..bb8a35ad1322c 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -115,6 +115,7 @@ typedef struct _zend_file_context { HashTable *imports_const; HashTable seen_symbols; + zend_long namespace_id; } zend_file_context; typedef union _zend_parser_stack_elem { diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 57e88e630dee6..dcd7a533105bd 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -244,7 +244,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*); %type variable_class_name dereferencable_scalar constant dereferencable %type callable_expr callable_variable static_member new_variable %type encaps_var encaps_var_offset isset_variables -%type top_statement_list use_declarations const_list inner_statement_list if_stmt +%type top_statement_list use_declarations const_list static_const_list inner_statement_list if_stmt %type alt_if_stmt for_exprs switch_case_list global_var_list static_var_list %type echo_expr_list unset_variables catch_name_list catch_list parameter_list class_statement_list %type implements_list case_list if_stmt_without_else @@ -334,6 +334,7 @@ top_statement: | T_USE use_declarations ';' { $$ = $2; $$->attr = ZEND_SYMBOL_CLASS; } | T_USE use_type use_declarations ';' { $$ = $3; $$->attr = $2; } | T_CONST const_list ';' { $$ = $2; } + | T_STATIC T_CONST static_const_list ';' { $$ = $3; } ; use_type: @@ -403,6 +404,11 @@ const_list: | const_decl { $$ = zend_ast_create_list(1, ZEND_AST_CONST_DECL, $1); } ; +static_const_list: + static_const_list ',' const_decl { $$ = zend_ast_list_add($1, $3); } + | const_decl { $$ = zend_ast_create_list(1, ZEND_AST_STATIC_CONST_DECL, $1); } +; + inner_statement_list: inner_statement_list inner_statement { $$ = zend_ast_list_add($1, $2); }