From 5585d4637f43f31f4851d32e700fa2031a3665cb Mon Sep 17 00:00:00 2001 From: Oguz Ulgen Date: Mon, 1 Nov 2021 21:56:32 -0700 Subject: [PATCH] Add reflection for readonly Summary: Add * ReflectionParameter::isReadonly * ReflectionProperty::isReadonly * ReflectionFunctionAbstract::returnsReadonly * ReflectionMethod::isReadonly Reviewed By: viratyosin Differential Revision: D32079586 fbshipit-source-id: d27e39b6ff7770068c54f03c0329f85515ad3b1a --- .../ext/reflection/ext_reflection-classes.php | 23 +++++++++------ hphp/runtime/ext/reflection/ext_reflection.cpp | 31 ++++++++++++++++++++ hphp/runtime/ext/reflection/ext_reflection_hni.php | 6 ++++ hphp/test/slow/readonly/reflection-1.php | 33 ++++++++++++++++++++++ hphp/test/slow/readonly/reflection-1.php.expect | 10 +++++++ 5 files changed, 95 insertions(+), 8 deletions(-) create mode 100644 hphp/test/slow/readonly/reflection-1.php create mode 100644 hphp/test/slow/readonly/reflection-1.php.expect diff --git a/hphp/runtime/ext/reflection/ext_reflection-classes.php b/hphp/runtime/ext/reflection/ext_reflection-classes.php index ffb115bf203..aa5045f4c0d 100644 --- a/hphp/runtime/ext/reflection/ext_reflection-classes.php +++ b/hphp/runtime/ext/reflection/ext_reflection-classes.php @@ -183,14 +183,9 @@ class ReflectionParameter implements Reflector { $type .= ' '; } $out = 'Parameter #'.(string)$this->getPosition().' [ '; - $inout = ''; - $reference = ''; - if ($this->isInOut()) { - $inout = 'inout '; - } else if ($this->isPassedByReference()) { - $reference = '&'; - } - $param = $inout.$type.$reference.'$'.(string)$this->getName(); + $inout = $this->isInOut() ? 'inout ' : ''; + $readonly = $this->isReadonly() ? 'readonly ' : ''; + $param = $readonly.$inout.$type.'$'.(string)$this->getName(); if ($this->isOptional()) { $default = var_export($this->getDefaultValue(), true); $out .= ' '.$param.' = '.(string)$default; @@ -294,6 +289,15 @@ class ReflectionParameter implements Reflector { return ($this->info['inout'] ?? false); } + /** + * Checks if this is a readonly parameter. + * + * @return bool TRUE if the parameter is readonly, otherwise FALSE + */ + public function isReadonly()[] { + return ($this->info['readonly'] ?? false); + } + // This doc comment block generated by idl/sysdoc.php /** * ( excerpt from @@ -951,6 +955,9 @@ class ReflectionProperty implements Reflector { return ($this->isPublic() || $this->forceAccessible); } + <<__Native>> + public function isReadonly()[]: bool; + /** * Get the value from the property declaration, which is what's set on the * property before we enter the constructor. If the property is dynamic, diff --git a/hphp/runtime/ext/reflection/ext_reflection.cpp b/hphp/runtime/ext/reflection/ext_reflection.cpp index 9eae1f47ed2..5011024b6f8 100644 --- a/hphp/runtime/ext/reflection/ext_reflection.cpp +++ b/hphp/runtime/ext/reflection/ext_reflection.cpp @@ -74,6 +74,7 @@ const StaticString s_prototype("prototype"), s_ref("ref"), s_inout("inout"), + s_readonly("readonly"), s_index("index"), s_type("type"), s_nullable("nullable"), @@ -803,6 +804,9 @@ static Array get_function_param_info(const Func* func) { if (func->isInOut(i)) { param.set(s_inout, make_tv(true)); } + if (func->isReadonly(i)) { + param.set(s_readonly, make_tv(true)); + } if (fpi.isVariadic()) { param.set(s_is_variadic, make_tv(true)); } @@ -924,6 +928,11 @@ static Array HHVM_METHOD(ReflectionFunctionAbstract, getCoeffects) { return arr.toArray(); } +static bool HHVM_METHOD(ReflectionFunctionAbstract, returnsReadonly) { + auto const func = ReflectionFuncHandle::GetFuncFor(this_); + return func->attrs() & AttrReadonlyReturn; +} + ALWAYS_INLINE static Array get_function_user_attributes(const Func* func) { auto userAttrs = func->userAttributes(); @@ -1000,6 +1009,11 @@ static bool HHVM_METHOD(ReflectionMethod, isConstructor) { return isConstructor(func); } +static bool HHVM_METHOD(ReflectionMethod, isReadonly) { + auto const func = ReflectionFuncHandle::GetFuncFor(this_); + return func->attrs() & AttrReadonlyThis; +} + static int HHVM_METHOD(ReflectionMethod, getModifiers) { auto const func = ReflectionFuncHandle::GetFuncFor(this_); return get_modifiers(func->attrs(), false, false); @@ -2084,6 +2098,20 @@ static Array HHVM_METHOD(ReflectionProperty, getAttributesNamespaced) { } } +static bool HHVM_METHOD(ReflectionProperty, isReadonly) { + auto const data = Native::data(this_); + switch (data->getType()) { + case ReflectionPropHandle::Type::Instance: + return data->getProp()->attrs & AttrIsReadonly; + case ReflectionPropHandle::Type::Static: + return data->getSProp()->attrs & AttrIsReadonly; + case ReflectionPropHandle::Type::Dynamic: + return false; + default: + reflection_property_internal_error(); + } +} + ///////////////////////////////////////////////////////////////////////////// // class ReflectionTypeAlias @@ -2178,6 +2206,7 @@ struct ReflectionExtension final : Extension { HHVM_ME(ReflectionFunctionAbstract, getRetTypeInfo); HHVM_ME(ReflectionFunctionAbstract, getReifiedTypeParamInfo); HHVM_ME(ReflectionFunctionAbstract, getCoeffects); + HHVM_ME(ReflectionFunctionAbstract, returnsReadonly); HHVM_ME(ReflectionMethod, __init); HHVM_ME(ReflectionMethod, isFinal); @@ -2188,6 +2217,7 @@ struct ReflectionExtension final : Extension { HHVM_ME(ReflectionMethod, isStatic); HHVM_ME(ReflectionMethod, isStaticInPrologue); HHVM_ME(ReflectionMethod, isConstructor); + HHVM_ME(ReflectionMethod, isReadonly); HHVM_ME(ReflectionMethod, getModifiers); HHVM_ME(ReflectionMethod, getPrototypeClassname); HHVM_ME(ReflectionMethod, getDeclaringClassname); @@ -2213,6 +2243,7 @@ struct ReflectionExtension final : Extension { HHVM_ME(ReflectionProperty, isPrivate); HHVM_ME(ReflectionProperty, isStatic); HHVM_ME(ReflectionProperty, isDefault); + HHVM_ME(ReflectionProperty, isReadonly); HHVM_ME(ReflectionProperty, getModifiers); HHVM_ME(ReflectionProperty, getDocComment); HHVM_ME(ReflectionProperty, getTypeText); diff --git a/hphp/runtime/ext/reflection/ext_reflection_hni.php b/hphp/runtime/ext/reflection/ext_reflection_hni.php index 325dcfda9f0..7729b841bce 100644 --- a/hphp/runtime/ext/reflection/ext_reflection_hni.php +++ b/hphp/runtime/ext/reflection/ext_reflection_hni.php @@ -229,6 +229,9 @@ abstract class ReflectionFunctionAbstract implements Reflector { <<__Native>> public function getCoeffects()[]: vec; + <<__Native>> + public function returnsReadonly()[]: bool; + /** * ( excerpt from * http://php.net/manual/en/reflectionfunctionabstract.hasreturntype.php @@ -908,6 +911,9 @@ class ReflectionMethod extends ReflectionFunctionAbstract { <<__Native>> public function isConstructor()[]: bool; + <<__Native>> + public function isReadonly()[]: bool; + /** * ( excerpt from * http://php.net/manual/en/reflectionmethod.getmodifiers.php ) diff --git a/hphp/test/slow/readonly/reflection-1.php b/hphp/test/slow/readonly/reflection-1.php new file mode 100644 index 00000000000..b03f731fbbb --- /dev/null +++ b/hphp/test/slow/readonly/reflection-1.php @@ -0,0 +1,33 @@ +> +function main() { + var_dump((new ReflectionParameter('C::f1', 'x1'))->isReadonly()); + var_dump((new ReflectionParameter('C::f1', 'x2'))->isReadonly()); + + var_dump((new ReflectionProperty('C', 'p1'))->isReadonly()); + var_dump((new ReflectionProperty('C', 'p2'))->isReadonly()); + + var_dump((new ReflectionFunction('f1'))->returnsReadonly()); + var_dump((new ReflectionFunction('f2'))->returnsReadonly()); + + var_dump((new ReflectionMethod('C::f1'))->returnsReadonly()); + var_dump((new ReflectionMethod('C::f2'))->returnsReadonly()); + + var_dump((new ReflectionMethod('C::f1'))->isReadonly()); + var_dump((new ReflectionMethod('C::f2'))->isReadonly()); +} diff --git a/hphp/test/slow/readonly/reflection-1.php.expect b/hphp/test/slow/readonly/reflection-1.php.expect new file mode 100644 index 00000000000..2c790b4001e --- /dev/null +++ b/hphp/test/slow/readonly/reflection-1.php.expect @@ -0,0 +1,10 @@ +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) -- 2.11.4.GIT