]> granicus.if.org Git - php/commitdiff
Add ReflectionMethod::setAccessible() for invoking non-public methods through the...
authorSebastian Bergmann <sebastian@php.net>
Thu, 10 Sep 2009 05:04:53 +0000 (05:04 +0000)
committerSebastian Bergmann <sebastian@php.net>
Thu, 10 Sep 2009 05:04:53 +0000 (05:04 +0000)
NEWS
ext/reflection/php_reflection.c
ext/reflection/tests/ReflectionMethod_setAccessible.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 60da3f5a1adeb6172ca90bf2036c5c940aaddeeb..eceae54d80ea9ee326e5181d40799a5b3a237ca2 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -45,6 +45,8 @@ PHP                                                                        NEWS
   (Sara)
 - Added stream_resolve_include_path() function which checks which file fopen()
   with a relative path will open. (Sara)
+- Added ReflectionMethod::setAccessible() for invoking non-public methods
+  through the Reflection API. (Sebastian)
 
 - Fixed bug #46647 (SplFileObject::fgetcsv segfaults). (Etienne)
 - Fixed bug #40325 (Vary: header missing in gzip output handlers). (Mike)
index f7192f723bb5e1f260751a5d52e6e0ea19cc3c26..9e91594150e35e35a79d07f7db31fb7abdf57849 100644 (file)
@@ -171,7 +171,6 @@ static void string_free(string *str)
 typedef struct _property_reference {
        zend_class_entry *ce;
        zend_property_info prop;
-       unsigned int ignore_visibility:1;
 } property_reference;
 
 /* Struct for parameters */
@@ -196,6 +195,7 @@ typedef struct {
        reflection_type_t ref_type;
        zval *obj;
        zend_class_entry *ce;
+       unsigned int ignore_visibility:1;
 } reflection_object;
 
 static zend_object_handlers reflection_object_handlers;
@@ -1293,10 +1293,10 @@ static void reflection_property_factory(zend_class_entry *ce, zend_property_info
        reference = (property_reference*) emalloc(sizeof(property_reference));
        reference->ce = ce;
        reference->prop = *prop;
-       reference->ignore_visibility = 0;
        intern->ptr = reference;
        intern->ref_type = REF_TYPE_PROPERTY;
        intern->ce = ce;
+       intern->ignore_visibility = 0;
        zend_ascii_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL);
        zend_ascii_hash_update(Z_OBJPROP_P(object), "class", sizeof("class"), (void **) &classname, sizeof(zval *), NULL);
 }
@@ -2701,8 +2701,9 @@ ZEND_METHOD(reflection_method, invoke)
        
        GET_REFLECTION_OBJECT_PTR(mptr);
 
-       if (!(mptr->common.fn_flags & ZEND_ACC_PUBLIC)
-               || (mptr->common.fn_flags & ZEND_ACC_ABSTRACT))
+       if ((!(mptr->common.fn_flags & ZEND_ACC_PUBLIC)
+                || (mptr->common.fn_flags & ZEND_ACC_ABSTRACT))
+                && intern->ignore_visibility == 0)
        {
                if (mptr->common.fn_flags & ZEND_ACC_ABSTRACT) {
                        zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, 
@@ -2804,8 +2805,9 @@ ZEND_METHOD(reflection_method, invokeArgs)
                return;
        }
 
-       if (!(mptr->common.fn_flags & ZEND_ACC_PUBLIC)
-               || (mptr->common.fn_flags & ZEND_ACC_ABSTRACT))
+       if ((!(mptr->common.fn_flags & ZEND_ACC_PUBLIC)
+                || (mptr->common.fn_flags & ZEND_ACC_ABSTRACT))
+                && intern->ignore_visibility == 0)
        {
                if (mptr->common.fn_flags & ZEND_ACC_ABSTRACT) {
                        zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, 
@@ -3109,6 +3111,28 @@ ZEND_METHOD(reflection_method, getPrototype)
 }
 /* }}} */
 
+/* {{{ proto public void ReflectionMethod::setAccessible()
+   Sets whether non-public methods can be invoked */
+ZEND_METHOD(reflection_method, setAccessible)
+{
+       reflection_object *intern;
+       zend_bool visible;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b", &visible) == FAILURE) {
+               return;
+       }
+
+       intern = getThis();
+       intern = (reflection_object *) zend_object_store_get_object(intern TSRMLS_CC);
+
+       if (intern == NULL) {
+               return;
+       }
+
+       intern->ignore_visibility = visible;
+}
+/* }}} */
+
 /* {{{ proto public static mixed ReflectionClass::export(mixed argument [, bool return]) throws ReflectionException U
    Exports a reflection object. Returns the output if TRUE is specified for return, printing it otherwise. */
 ZEND_METHOD(reflection_class, export)
@@ -4580,10 +4604,10 @@ ZEND_METHOD(reflection_property, __construct)
                reference->prop = *property_info;
        }
        reference->ce = ce;
-       reference->ignore_visibility = 0;
        intern->ptr = reference;
        intern->ref_type = REF_TYPE_PROPERTY;
        intern->ce = ce;
+       intern->ignore_visibility = 0;
 }
 /* }}} */
 
@@ -4730,7 +4754,7 @@ ZEND_METHOD(reflection_property, getValue)
        METHOD_NOTSTATIC(reflection_property_ptr);
        GET_REFLECTION_OBJECT_PTR(ref);
 
-       if (!(ref->prop.flags & (ZEND_ACC_PUBLIC | ZEND_ACC_IMPLICIT_PUBLIC)) && ref->ignore_visibility == 0) {
+       if (!(ref->prop.flags & (ZEND_ACC_PUBLIC | ZEND_ACC_IMPLICIT_PUBLIC)) && intern->ignore_visibility == 0) {
                _default_get_entry(getThis(), "name", sizeof("name"), &name TSRMLS_CC);
                zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, 
                        "Cannot access non-public member %v::%v", intern->ce->name, Z_UNIVAL(name));
@@ -4785,7 +4809,7 @@ ZEND_METHOD(reflection_property, setValue)
        METHOD_NOTSTATIC(reflection_property_ptr);
        GET_REFLECTION_OBJECT_PTR(ref);
 
-       if (!(ref->prop.flags & ZEND_ACC_PUBLIC) && ref->ignore_visibility == 0) {
+       if (!(ref->prop.flags & ZEND_ACC_PUBLIC) && intern->ignore_visibility == 0) {
                _default_get_entry(getThis(), "name", sizeof("name"), &name TSRMLS_CC);
                zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, 
                        "Cannot access non-public member %v::%v", intern->ce->name, Z_UNIVAL(name));
@@ -4904,14 +4928,20 @@ ZEND_METHOD(reflection_property, getDocComment)
 ZEND_METHOD(reflection_property, setAccessible)
 {
        reflection_object *intern;
-       property_reference *ref;
        zend_bool visible;
 
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b", &visible) == FAILURE) {
                return;
        }
-       GET_REFLECTION_OBJECT_PTR(ref);
-       ref->ignore_visibility = visible;
+
+       intern = getThis();
+       intern = (reflection_object *) zend_object_store_get_object(intern TSRMLS_CC);
+
+       if (intern == NULL) {
+               return;
+       }
+
+       intern->ignore_visibility = visible;
 }
 /* }}} */
 
@@ -5342,6 +5372,10 @@ ZEND_BEGIN_ARG_INFO(arginfo_reflection_method_invokeArgs, 0)
        ZEND_ARG_ARRAY_INFO(0, args, 0)
 ZEND_END_ARG_INFO()
 
+ZEND_BEGIN_ARG_INFO(arginfo_reflection_method_setAccessible, 0)
+       ZEND_ARG_INFO(0, value)
+ZEND_END_ARG_INFO()
+
 static const zend_function_entry reflection_method_functions[] = {
        ZEND_ME(reflection_method, export, arginfo_reflection_method_export, ZEND_ACC_STATIC|ZEND_ACC_PUBLIC)
        ZEND_ME(reflection_method, __construct, arginfo_reflection_method___construct, 0)
@@ -5360,6 +5394,7 @@ static const zend_function_entry reflection_method_functions[] = {
        ZEND_ME(reflection_method, invokeArgs, arginfo_reflection_method_invokeArgs, 0)
        ZEND_ME(reflection_method, getDeclaringClass, NULL, 0)
        ZEND_ME(reflection_method, getPrototype, NULL, 0)
+       ZEND_ME(reflection_property, setAccessible, arginfo_reflection_method_setAccessible, 0)
        {NULL, NULL, NULL}
 };
 
diff --git a/ext/reflection/tests/ReflectionMethod_setAccessible.phpt b/ext/reflection/tests/ReflectionMethod_setAccessible.phpt
new file mode 100644 (file)
index 0000000..7f2c7ea
--- /dev/null
@@ -0,0 +1,111 @@
+--TEST--
+Test ReflectionMethod::setAccessible().
+--FILE--
+<?php
+class A {
+    private function aPrivate($a) { print __METHOD__ . "\n"; }
+    private static function aPrivateStatic($a) { print __METHOD__ . "\n"; }
+    protected function aProtected($a) { print __METHOD__ . "\n"; }
+    protected static function aProtectedStatic($a) { print __METHOD__ . "\n"; }
+}
+
+$private         = new ReflectionMethod('A', 'aPrivate');
+$privateStatic   = new ReflectionMethod('A', 'aPrivateStatic');
+$protected       = new ReflectionMethod('A', 'aProtected');
+$protectedStatic = new ReflectionMethod('A', 'aProtectedStatic');
+
+try {
+    $private->invoke(new A, NULL);
+}
+
+catch (ReflectionException $e) {
+    var_dump($e->getMessage());
+}
+
+try {
+    $private->invokeArgs(new A, array(NULL));
+}
+
+catch (ReflectionException $e) {
+    var_dump($e->getMessage());
+}
+
+try {
+    $privateStatic->invoke(NULL, NULL);
+}
+
+catch (ReflectionException $e) {
+    var_dump($e->getMessage());
+}
+
+try {
+    $privateStatic->invokeArgs(NULL, array(NULL));
+}
+
+catch (ReflectionException $e) {
+    var_dump($e->getMessage());
+}
+
+try {
+    $protected->invoke(new A, NULL);
+}
+
+catch (ReflectionException $e) {
+    var_dump($e->getMessage());
+}
+
+try {
+    $protected->invokeArgs(new A, array(NULL));
+}
+
+catch (ReflectionException $e) {
+    var_dump($e->getMessage());
+}
+
+try {
+    $protectedStatic->invoke(NULL, NULL);
+}
+
+catch (ReflectionException $e) {
+    var_dump($e->getMessage());
+}
+
+try {
+    $protectedStatic->invokeArgs(NULL, array(NULL));
+}
+
+catch (ReflectionException $e) {
+    var_dump($e->getMessage());
+}
+
+$private->setAccessible(TRUE);
+$privateStatic->setAccessible(TRUE);
+$protected->setAccessible(TRUE);
+$protectedStatic->setAccessible(TRUE);
+
+$private->invoke(new A, NULL);
+$private->invokeArgs(new A, array(NULL));
+$privateStatic->invoke(NULL, NULL);
+$privateStatic->invokeArgs(NULL, array(NULL));
+$protected->invoke(new A, NULL);
+$protected->invokeArgs(new A, array(NULL));
+$protectedStatic->invoke(NULL, NULL);
+$protectedStatic->invokeArgs(NULL, array(NULL));
+?>
+--EXPECT--
+unicode(73) "Trying to invoke private method A::aPrivate() from scope ReflectionMethod"
+unicode(73) "Trying to invoke private method A::aPrivate() from scope ReflectionMethod"
+unicode(79) "Trying to invoke private method A::aPrivateStatic() from scope ReflectionMethod"
+unicode(79) "Trying to invoke private method A::aPrivateStatic() from scope ReflectionMethod"
+unicode(77) "Trying to invoke protected method A::aProtected() from scope ReflectionMethod"
+unicode(77) "Trying to invoke protected method A::aProtected() from scope ReflectionMethod"
+unicode(83) "Trying to invoke protected method A::aProtectedStatic() from scope ReflectionMethod"
+unicode(83) "Trying to invoke protected method A::aProtectedStatic() from scope ReflectionMethod"
+A::aPrivate
+A::aPrivate
+A::aPrivateStatic
+A::aPrivateStatic
+A::aProtected
+A::aProtected
+A::aProtectedStatic
+A::aProtectedStatic