从PHP5开始,我们通过反射类来访问私有方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<?php class TestClass { private $_test_count = 1; private function incr($inc_count) { self::incr_count($this->_test_count, $inc_count); return $this; } private static function incr_count(&$count, $inc_count) { $count += $inc_count; } } |
以下是反射方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
class KlassHelper { static function visit_private_static_method($klass, $method, $data) { $m = new ReflectionMethod($klass, $method); $m->setAccessible(TRUE); if (is_array($data)) { $data = array_merge([$klass], $data); } else { $data = [$klass, $data]; } $result = call_user_func_array([$m, 'invoke'], $data); return $result; } static function visit_private_method($klass, $method, $data) { $c = new $klass(); $m = new ReflectionMethod($c, $method); $m->setAccessible(TRUE); if (is_array($data)) { $data = array_merge([$c], $data); } else { $data = [$c, $data]; } $result = call_user_func_array([$m, 'invoke'], $data); return $result; } static function visit_private_property($klass, $property, $object) { $reflection = new ReflectionClass($klass); $p = $reflection->getProperty($property); $p->setAccessible(true); return $p->getValue($object); } } |
访问私有方法和属性:
1 2 3 4 5 6 7 8 9 10 11 |
$test_class =new TestClass(); $kls = KlassHelper::visit_private_method($test_class, 'incr', [10]); $count_1 = KlassHelper::visit_private_property('TestClass', '_test_count', $kls); echo $count_1.PHP_EOL; // 11 $count_2 = KlassHelper::visit_private_property('TestClass', '_test_count', $test_class); echo $count_2.PHP_EOL; // 1 $test_count = 5; KlassHelper::visit_private_static_method('TestClass', 'incr_count', [&$test_count, 10]); echo $test_count.PHP_EOL; // 5 |
通过反射拿回来数据进行输出,我们发现,经过反射获取到的属性不是属于原来的对象的,而是属于反射产生的对象。
我们还发现,虽然传入的是引用,但是因为某些情况,到处传出的数据仍然没有变化($test_count传入的是5,加11后返回还是5)。
在php5.4以后,我们可以通过闭包的方式来获取私有方法处理过的引用的值:
1 2 3 4 5 6 7 8 9 |
$test_count = 5; // 一个闭包调用 $cl = static function (&$count, $incr) { TestClass::incr_count($count, $incr); }; // 将TestClass的作用域绑定到闭包上 $bcl = Closure::bind($cl, null, 'TestClass'); $bcl($test_count, 10); echo $test_count.PHP_EOL; // 15 |
通过将作用域绑定到复制出的$bcl闭包上,这样我们可以更方便的访问对象里的值。
相关内容,大家可以参考以下文档:
好厉害
踩,忽然觉得我来这也就是踩踩了。。。
你不是一直这样嘛……