]> granicus.if.org Git - php/commitdiff
Implement ReflectionClass::setFinal() and ReflectionMethod::setFinal().
authorSebastian Bergmann <sebastian@php.net>
Tue, 17 Jan 2012 12:59:33 +0000 (12:59 +0000)
committerSebastian Bergmann <sebastian@php.net>
Tue, 17 Jan 2012 12:59:33 +0000 (12:59 +0000)
Patch by Jan Dolecek <juzna.cz@gmail.com>.

NEWS
ext/reflection/php_reflection.c
ext/reflection/tests/ReflectionClass_setFinal.phpt [new file with mode: 0644]
ext/reflection/tests/ReflectionClass_toString_001.phpt
ext/reflection/tests/ReflectionMethod_setFinal.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 0cf44aa4d759853943c7b4d83f59a758daf52b4a..5a7ca1480ac4027785ae1b06c614c1b1292d97a4 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -35,4 +35,9 @@ PHP                                                                        NEWS
 - pgsql
   . Added pg_escape_literal() and pg_escape_identifier() (Yasuo)
 
+- Reflection:
+  . Added ReflectionCLass::setFinal() and ReflectionMethod::setFinal() to allow
+    stubbing and mocking of final classes and methods, for instance.
+    (Sebastian, Jan Dolecek <juzna.cz@gmail.com>)
+
 <<< NOTE: Insert NEWS from last stable release here prior to actual release! >>>
index 663eb405ded5c4fbd3458a4631b0c2f4c2cdb83e..8fccd90547a677db278bfd1ffa1fcd18b282813f 100644 (file)
@@ -3113,6 +3113,28 @@ ZEND_METHOD(reflection_method, getModifiers)
 }
 /* }}} */
 
+/* {{{ proto public void ReflectionMethod::setFinal([bool isFinal = true])
+      Sets/unsets class as final */
+ZEND_METHOD(reflection_method, setFinal)
+{
+       reflection_object *intern;
+       zend_function *mptr;
+       zend_bool isFinal = 1;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &isFinal) == FAILURE) {
+               return;
+       }
+
+       GET_REFLECTION_OBJECT_PTR(mptr);
+
+       if (isFinal) {
+               mptr->common.fn_flags |= ZEND_ACC_FINAL;
+       } else {
+               mptr->common.fn_flags &= ~ZEND_ACC_FINAL;
+       }
+}
+/* }}} */
+
 /* {{{ proto public ReflectionClass ReflectionMethod::getDeclaringClass()
    Get the declaring class */
 ZEND_METHOD(reflection_method, getDeclaringClass)
@@ -4047,6 +4069,28 @@ ZEND_METHOD(reflection_class, isAbstract)
 }
 /* }}} */
 
+/* {{{ proto public void ReflectionClass::setFinal([bool isFinal = true])
+   Sets/unsets class as final */
+ZEND_METHOD(reflection_class, setFinal)
+{
+       reflection_object *intern;
+       zend_class_entry *ce;
+       zend_bool isFinal = 1;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &isFinal) == FAILURE) {
+               return;
+       }
+
+       GET_REFLECTION_OBJECT_PTR(ce);
+
+       if (isFinal) {
+               ce->ce_flags |= ZEND_ACC_FINAL_CLASS;
+       } else {
+               ce->ce_flags &= ~ZEND_ACC_FINAL_CLASS;
+       }
+}
+/* }}} */
+
 /* {{{ proto public int ReflectionClass::getModifiers()
    Returns a bitfield of the access modifiers for this class */
 ZEND_METHOD(reflection_class, getModifiers)
@@ -5651,6 +5695,10 @@ ZEND_BEGIN_ARG_INFO(arginfo_reflection_method_setAccessible, 0)
        ZEND_ARG_INFO(0, value)
 ZEND_END_ARG_INFO()
 
+ZEND_BEGIN_ARG_INFO(arginfo_reflection_method_setFinal, 0)
+       ZEND_ARG_INFO(0, value)
+ZEND_END_ARG_INFO()
+
 ZEND_BEGIN_ARG_INFO(arginfo_reflection_method_getClosure, 0)
        ZEND_ARG_INFO(0, object)
 ZEND_END_ARG_INFO()
@@ -5664,6 +5712,7 @@ static const zend_function_entry reflection_method_functions[] = {
        ZEND_ME(reflection_method, isProtected, arginfo_reflection__void, 0)
        ZEND_ME(reflection_method, isAbstract, arginfo_reflection__void, 0)
        ZEND_ME(reflection_method, isFinal, arginfo_reflection__void, 0)
+       ZEND_ME(reflection_method, setFinal, arginfo_reflection_method_setFinal, 0)
        ZEND_ME(reflection_method, isStatic, arginfo_reflection__void, 0)
        ZEND_ME(reflection_method, isConstructor, arginfo_reflection__void, 0)
        ZEND_ME(reflection_method, isDestructor, arginfo_reflection__void, 0)
@@ -5733,6 +5782,10 @@ ZEND_BEGIN_ARG_INFO(arginfo_reflection_class_isInstance, 0)
        ZEND_ARG_INFO(0, object)
 ZEND_END_ARG_INFO()
 
+ZEND_BEGIN_ARG_INFO(arginfo_reflection_class_setFinal, 0)
+       ZEND_ARG_INFO(0, value)
+ZEND_END_ARG_INFO()
+
 ZEND_BEGIN_ARG_INFO(arginfo_reflection_class_newInstance, 0)
        ZEND_ARG_INFO(0, args)
 ZEND_END_ARG_INFO()
@@ -5785,6 +5838,7 @@ static const zend_function_entry reflection_class_functions[] = {
        ZEND_ME(reflection_class, isTrait, arginfo_reflection__void, 0)
        ZEND_ME(reflection_class, isAbstract, arginfo_reflection__void, 0)
        ZEND_ME(reflection_class, isFinal, arginfo_reflection__void, 0)
+       ZEND_ME(reflection_class, setFinal, arginfo_reflection_class_setFinal, 0)
        ZEND_ME(reflection_class, getModifiers, arginfo_reflection__void, 0)
        ZEND_ME(reflection_class, isInstance, arginfo_reflection_class_isInstance, 0)
        ZEND_ME(reflection_class, newInstance, arginfo_reflection_class_newInstance, 0)
diff --git a/ext/reflection/tests/ReflectionClass_setFinal.phpt b/ext/reflection/tests/ReflectionClass_setFinal.phpt
new file mode 100644 (file)
index 0000000..dfd98f3
--- /dev/null
@@ -0,0 +1,33 @@
+--TEST--
+Test ReflectionClass::setFinal().
+--FILE--
+<?php
+class a {
+    public final function b() {
+        print __METHOD__;
+    }
+}
+
+$c = new ReflectionClass('a');
+$c->setFinal(FALSE);
+
+var_dump($c->isFinal());
+
+# Not sure if it is by design that the following two lines are required
+$m = new ReflectionMethod('a', 'b');
+$m->setFinal(FALSE);
+
+if (TRUE) {
+    class c extends a {
+        public function b() {
+            print __METHOD__;
+        }
+    }
+}
+
+$o = new c;
+$o->b();
+?>
+--EXPECT--
+bool(false)
+c::b
index 508530a5478fb008d6c2e333477d3d1c664a7cdd..35ae07c884591a2119d617c34cede2c6bdab8c21 100644 (file)
@@ -8,7 +8,7 @@ Steve Seear <stevseea@php.net>
 $rc = new ReflectionClass("ReflectionClass");
 echo $rc;
 ?>
---EXPECTF--
+--EXPECT--
 Class [ <internal:Reflection> class ReflectionClass implements Reflector ] {
 
   - Constants [3] {
@@ -34,7 +34,7 @@ Class [ <internal:Reflection> class ReflectionClass implements Reflector ] {
     Property [ <default> public $name ]
   }
 
-  - Methods [49] {
+  - Methods [50] {
     Method [ <internal:Reflection> final private method __clone ] {
 
       - Parameters [0] {
@@ -230,6 +230,13 @@ Class [ <internal:Reflection> class ReflectionClass implements Reflector ] {
       }
     }
 
+    Method [ <internal:Reflection> public method setFinal ] {
+
+      - Parameters [1] {
+        Parameter #0 [ <required> $value ]
+      }
+    }
+
     Method [ <internal:Reflection> public method getModifiers ] {
 
       - Parameters [0] {
diff --git a/ext/reflection/tests/ReflectionMethod_setFinal.phpt b/ext/reflection/tests/ReflectionMethod_setFinal.phpt
new file mode 100644 (file)
index 0000000..19d3ac8
--- /dev/null
@@ -0,0 +1,29 @@
+--TEST--
+Test ReflectionMethod::setFinal().
+--FILE--
+<?php
+class a {
+    public final function b() {
+        print __METHOD__;
+    }
+}
+
+$m = new ReflectionMethod('a', 'b');
+$m->setFinal(FALSE);
+
+var_dump($m->isFinal());
+
+if (TRUE) {
+    class c extends a {
+        public function b() {
+            print __METHOD__;
+        }
+    }
+}
+
+$o = new c;
+$o->b();
+?>
+--EXPECT--
+bool(false)
+c::b