Implement ReflectionClass::setFinal() and ReflectionMethod::setFinal().

Patch by Jan Dolecek <juzna.cz@gmail.com>.
This commit is contained in:
Sebastian Bergmann 2012-01-17 12:59:33 +00:00
parent 9025d6219d
commit e76c1cc03c
5 changed files with 130 additions and 2 deletions

5
NEWS
View file

@ -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! >>>

View 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)

View file

@ -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

View 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] {

View file

@ -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