]> granicus.if.org Git - php/commitdiff
Support parent::class inside constexpr contexts
authorNikita Popov <nikita.ppv@gmail.com>
Fri, 4 Jan 2019 10:38:35 +0000 (11:38 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Fri, 4 Jan 2019 10:46:57 +0000 (11:46 +0100)
Zend/tests/class_name_as_scalar_error_002.phpt
Zend/tests/class_name_as_scalar_error_004.phpt
Zend/zend_ast.c
Zend/zend_compile.c

index 59b7a2edc9acc17b099cd2ed268394870e7cdde2..3abba7f7fe589b0e9145aa40dd6bf9cf170c885c 100644 (file)
@@ -7,7 +7,11 @@ namespace Foo\Bar {
     class One {
         const Baz = parent::class;
     }
+    var_dump(One::Baz);
 }
 ?>
 --EXPECTF--
-Fatal error: parent::class cannot be used for compile-time class name resolution in %s on line %d
+Fatal error: Uncaught Error: Cannot use "parent" when current class scope has no parent in %s:%d
+Stack trace:
+#0 {main}
+  thrown in %s on line %d
index c00037fca3e15bdf7d710f15c023fe0ac3805435..5b743df2dbf162414be82f26b0809c6c46ac650e 100644 (file)
@@ -4,10 +4,14 @@ class name as scalar from ::class keyword error using parent in method signature
 <?php
 
 namespace Foo\Bar {
-    class One {
-        public function baz($x = parent::class) {}
+    class One {}
+    class Two extends One {
+        public function baz($x = parent::class) {
+            var_dump($x);
+        }
     }
+    (new Two)->baz();
 }
 ?>
---EXPECTF--
-Fatal error: parent::class cannot be used for compile-time class name resolution in %s on line %d
+--EXPECT--
+string(11) "Foo\Bar\One"
index bea20f646b33e1295afac15caf5b2f4666d5ac98..08fde1d1b09e05c944e033d144044bab61f4537b 100644 (file)
@@ -511,19 +511,28 @@ ZEND_API int ZEND_FASTCALL zend_ast_evaluate(zval *result, zend_ast *ast, zend_c
                        break;
                }
                case ZEND_AST_CONSTANT_CLASS:
-                       if (scope && scope->name) {
+                       if (scope) {
                                ZVAL_STR_COPY(result, scope->name);
                        } else {
                                ZVAL_EMPTY_STRING(result);
                        }
                        break;
                case ZEND_AST_CLASS_NAME:
-                       ZEND_ASSERT(ast->attr == ZEND_FETCH_CLASS_SELF);
-                       if (scope && scope->name) {
+                       if (!scope) {
+                               zend_throw_error(NULL, "Cannot use \"self\" when no class scope is active");
+                               return FAILURE;
+                       }
+                       if (ast->attr == ZEND_FETCH_CLASS_SELF) {
                                ZVAL_STR_COPY(result, scope->name);
+                       } else if (ast->attr == ZEND_FETCH_CLASS_PARENT) {
+                               if (!scope->parent) {
+                                       zend_throw_error(NULL,
+                                               "Cannot use \"parent\" when current class scope has no parent");
+                                       return FAILURE;
+                               }
+                               ZVAL_STR_COPY(result, scope->parent->name);
                        } else {
-                               zend_throw_error(NULL, "Cannot use \"self\" when no class scope is active");
-                               ret = FAILURE;
+                               ZEND_ASSERT(0 && "Should have errored during compilation");
                        }
                        break;
                case ZEND_AST_AND:
index 30a648f3269f6827ab494115efb3820501730038..3dc19a30b1ac4cf461d43ab301b583cf393dcec5 100644 (file)
@@ -7958,18 +7958,20 @@ void zend_compile_const_expr_class_name(zend_ast **ast_ptr) /* {{{ */
        zend_string *class_name = zend_ast_get_str(class_ast);
        uint32_t fetch_type = zend_get_class_fetch_type(class_name);
 
-       /* For the const-eval representation store the fetch type instead of the name. */
-       if (fetch_type == ZEND_FETCH_CLASS_SELF) {
-               zend_string_release(class_name);
-               ast->child[0] = NULL;
-               ast->attr = fetch_type;
-               return;
+       switch (fetch_type) {
+               case ZEND_FETCH_CLASS_SELF:
+               case ZEND_FETCH_CLASS_PARENT:
+                       /* For the const-eval representation store the fetch type instead of the name. */
+                       zend_string_release(class_name);
+                       ast->child[0] = NULL;
+                       ast->attr = fetch_type;
+                       return;
+               case ZEND_FETCH_CLASS_STATIC:
+                       zend_error_noreturn(E_COMPILE_ERROR,
+                               "static::class cannot be used for compile-time class name resolution");
+                       return;
+               EMPTY_SWITCH_DEFAULT_CASE()
        }
-
-       zend_error_noreturn(E_COMPILE_ERROR,
-               "%s::class cannot be used for compile-time class name resolution",
-               fetch_type == ZEND_FETCH_CLASS_STATIC ? "static" : "parent"
-       );
 }
 
 void zend_compile_const_expr_const(zend_ast **ast_ptr) /* {{{ */