]> granicus.if.org Git - php/commitdiff
Add ReflectionProperty::getDefaultValue and ReflectionProperty::hasDefaultValue
authorBenjamin Eberlei <kontakt@beberlei.de>
Thu, 9 Jan 2020 21:51:15 +0000 (22:51 +0100)
committerBenjamin Eberlei <kontakt@beberlei.de>
Wed, 22 Jan 2020 20:24:36 +0000 (21:24 +0100)
ext/reflection/php_reflection.c
ext/reflection/reflection.stub.php
ext/reflection/reflection_arginfo.h
ext/reflection/tests/ReflectionProperty_getDefaultValue.phpt [new file with mode: 0644]
ext/reflection/tests/ReflectionProperty_hasDefaultValue.phpt [new file with mode: 0644]

index d53862fba754e11cb8016b45d1647e5f408107cb..e1c41e5ec5e007583b6feaebe0f30a5b964d3a09 100644 (file)
@@ -5686,6 +5686,90 @@ ZEND_METHOD(reflection_property, hasType)
 }
 /* }}} */
 
+/* {{{ proto public bool ReflectionProperty::hasDefaultValue()
+   Returns whether property has a default value */
+ZEND_METHOD(reflection_property, hasDefaultValue)
+{
+       reflection_object *intern;
+       property_reference *ref;
+       zend_property_info *prop_info;
+       zval *prop;
+       zend_class_entry *ce;
+
+       if (zend_parse_parameters_none() == FAILURE) {
+               RETURN_THROWS();
+       }
+
+       GET_REFLECTION_OBJECT_PTR(ref);
+
+       prop_info = ref->prop;
+
+       if (prop_info == NULL) {
+               RETURN_FALSE;
+       }
+
+       ce = prop_info->ce;
+
+       if ((prop_info->flags & ZEND_ACC_STATIC) != 0) {
+               prop = &ce->default_static_members_table[prop_info->offset];
+               ZVAL_DEINDIRECT(prop);
+       } else {
+               prop = &ce->default_properties_table[OBJ_PROP_TO_NUM(prop_info->offset)];
+       }
+
+       RETURN_BOOL(!Z_ISUNDEF_P(prop));
+}
+/* }}} */
+
+/* {{{ proto public mixed ReflectionProperty::getDefaultValue()
+   Returns the default value of a property */
+ZEND_METHOD(reflection_property, getDefaultValue)
+{
+       reflection_object *intern;
+       property_reference *ref;
+       zend_property_info *prop_info;
+       zval *prop;
+       zend_class_entry *ce;
+
+       if (zend_parse_parameters_none() == FAILURE) {
+               RETURN_THROWS();
+       }
+
+       GET_REFLECTION_OBJECT_PTR(ref);
+
+       prop_info = ref->prop;
+
+       if (prop_info == NULL) {
+               return; // throw exception?
+       }
+
+       ce = prop_info->ce;
+
+       if ((prop_info->flags & ZEND_ACC_STATIC) != 0) {
+               prop = &ce->default_static_members_table[prop_info->offset];
+               ZVAL_DEINDIRECT(prop);
+       } else {
+               prop = &ce->default_properties_table[OBJ_PROP_TO_NUM(prop_info->offset)];
+       }
+
+       if (Z_ISUNDEF_P(prop)) {
+               return;
+       }
+
+       /* copy: enforce read only access */
+       ZVAL_DEREF(prop);
+       ZVAL_COPY_OR_DUP(return_value, prop);
+
+       /* this is necessary to make it able to work with default array
+       * properties, returned to user */
+       if (Z_TYPE_P(return_value) == IS_CONSTANT_AST) {
+               if (UNEXPECTED(zval_update_constant_ex(return_value, ce) != SUCCESS)) {
+                       RETURN_THROWS();
+               }
+       }
+}
+/* }}} */
+
 /* {{{ proto public static mixed ReflectionExtension::export(string name [, bool return]) throws ReflectionException
    Exports a reflection object. Returns the output if TRUE is specified for return, printing it otherwise. */
 ZEND_METHOD(reflection_extension, export)
@@ -6461,6 +6545,8 @@ static const zend_function_entry reflection_property_functions[] = {
        ZEND_ME(reflection_property, setAccessible, arginfo_class_ReflectionProperty_setAccessible, 0)
        ZEND_ME(reflection_property, getType, arginfo_class_ReflectionProperty_getType, 0)
        ZEND_ME(reflection_property, hasType, arginfo_class_ReflectionProperty_hasType, 0)
+       ZEND_ME(reflection_property, hasDefaultValue, arginfo_class_ReflectionProperty_hasDefaultValue, 0)
+       ZEND_ME(reflection_property, getDefaultValue, arginfo_class_ReflectionProperty_getDefaultValue, 0)
        PHP_FE_END
 };
 
index 11bb6c64338b4fb48ad78ffce66dacd6515e788b..26e38ae37f057006597f8bdfb82ded9f06c302f0 100644 (file)
@@ -425,6 +425,11 @@ class ReflectionProperty implements Reflector
 
     /** @return bool */
     public function hasType() {}
+
+    public function hasDefaultValue(): bool {}
+
+    /** @return mixed */
+    public function getDefaultValue() {}
 }
 
 class ReflectionClassConstant implements Reflector
index 078a793c9b6cf13902e8fe73a77c41b6a57377b6..68d61026b0e0740f6e3364ce0cf99f5daa553abc 100644 (file)
@@ -343,6 +343,11 @@ ZEND_END_ARG_INFO()
 
 #define arginfo_class_ReflectionProperty_hasType arginfo_class_Reflector___toString
 
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ReflectionProperty_hasDefaultValue, 0, 0, _IS_BOOL, 0)
+ZEND_END_ARG_INFO()
+
+#define arginfo_class_ReflectionProperty_getDefaultValue arginfo_class_Reflector___toString
+
 #define arginfo_class_ReflectionClassConstant___clone arginfo_class_Reflector___toString
 
 #define arginfo_class_ReflectionClassConstant_export arginfo_class_ReflectionMethod_export
diff --git a/ext/reflection/tests/ReflectionProperty_getDefaultValue.phpt b/ext/reflection/tests/ReflectionProperty_getDefaultValue.phpt
new file mode 100644 (file)
index 0000000..26614f5
--- /dev/null
@@ -0,0 +1,73 @@
+--TEST--
+reflection: ReflectionProperty::getDefaultValue
+--FILE--
+<?php
+
+define('FOO', 42);
+
+class TestClass
+{
+    public $foo;
+    public $bar = 'baz';
+
+    public static $static1;
+    public static $static2 = 1234;
+
+    public int $val1;
+    public int $val2 = 1234;
+
+    public ?int $nullable;
+    public ?int $nullable2 = null;
+
+    public $constantAst = 2 * 2;
+    public $constantRuntimeAst = FOO;
+}
+
+$property = new ReflectionProperty(TestClass::class, 'foo');
+var_dump($property->getDefaultValue());
+
+$property = new ReflectionProperty(TestClass::class, 'bar');
+var_dump($property->getDefaultValue());
+
+$property = new ReflectionProperty(TestClass::class, 'static1');
+var_dump($property->getDefaultValue());
+
+$property = new ReflectionProperty(TestClass::class, 'static2');
+var_dump($property->getDefaultValue());
+
+$property = new ReflectionProperty(TestClass::class, 'val1');
+var_dump($property->getDefaultValue());
+
+$property = new ReflectionProperty(TestClass::class, 'val2');
+var_dump($property->getDefaultValue());
+
+$property = new ReflectionProperty(TestClass::class, 'nullable');
+var_dump($property->getDefaultValue());
+
+$property = new ReflectionProperty(TestClass::class, 'nullable2');
+var_dump($property->getDefaultValue());
+
+$property = new ReflectionProperty(TestClass::class, 'constantAst');
+var_dump($property->getDefaultValue());
+
+$property = new ReflectionProperty(TestClass::class, 'constantRuntimeAst');
+var_dump($property->getDefaultValue());
+
+$test = new TestClass;
+$test->dynamic = null;
+$property = new ReflectionProperty($test, 'dynamic');
+var_dump($property->getDefaultValue());
+
+?>
+--EXPECT--
+NULL
+string(3) "baz"
+NULL
+int(1234)
+NULL
+int(1234)
+NULL
+NULL
+int(4)
+int(42)
+NULL
diff --git a/ext/reflection/tests/ReflectionProperty_hasDefaultValue.phpt b/ext/reflection/tests/ReflectionProperty_hasDefaultValue.phpt
new file mode 100644 (file)
index 0000000..5709000
--- /dev/null
@@ -0,0 +1,60 @@
+--TEST--
+reflection: ReflectionProperty::hasDefaultValue
+--FILE--
+<?php
+
+class TestClass
+{
+    public $foo;
+    public $bar = 'baz';
+
+    public static $static1;
+    public static $static2 = 1234;
+
+    public int $val1;
+    public int $val2 = 1234;
+
+    public ?int $nullable;
+    public ?int $nullable2 = null;
+}
+
+$property = new ReflectionProperty(TestClass::class, 'foo');
+var_dump($property->hasDefaultValue());
+
+$property = new ReflectionProperty(TestClass::class, 'bar');
+var_dump($property->hasDefaultValue());
+
+$property = new ReflectionProperty(TestClass::class, 'static1');
+var_dump($property->hasDefaultValue());
+
+$property = new ReflectionProperty(TestClass::class, 'static2');
+var_dump($property->hasDefaultValue());
+
+$property = new ReflectionProperty(TestClass::class, 'val1');
+var_dump($property->hasDefaultValue());
+
+$property = new ReflectionProperty(TestClass::class, 'val2');
+var_dump($property->hasDefaultValue());
+
+$property = new ReflectionProperty(TestClass::class, 'nullable');
+var_dump($property->hasDefaultValue());
+
+$property = new ReflectionProperty(TestClass::class, 'nullable2');
+var_dump($property->hasDefaultValue());
+
+$test = new TestClass;
+$test->dynamic = null;
+$property = new ReflectionProperty($test, 'dynamic');
+var_dump($property->hasDefaultValue());
+
+?>
+--EXPECT--
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(false)
+bool(true)
+bool(false)
+bool(true)
+bool(false)