Pab*_*res 16 php visibility introspection
我想在非常罕见的特定情况下从类外部访问私有方法和变量.
我已经看到尽管使用了内省,但这是不可能的.
具体案例是下一个案例:
我想要这样的东西:
class Console
{
final public static function run() {
while (TRUE != FALSE) {
echo "\n> ";
$command = trim(fgets(STDIN));
switch ($command) {
case 'exit':
case 'q':
case 'quit':
echo "OK+\n";
return;
default:
ob_start();
eval($command);
$out = ob_get_contents();
ob_end_clean();
print("Command: $command");
print("Output:\n$out");
break;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
这个方法应该能够像这样注入代码中:
Class Demo
{
private $a;
final public function myMethod()
{
// some code
Console::run();
// some other code
}
final public function myPublicMethod()
{
return "I can run through eval()";
}
private function myPrivateMethod()
{
return "I cannot run through eval()";
}
}
Run Code Online (Sandbox Code Playgroud)
(这只是一个简化.真正的一个通过套接字,并实现了一堆更多的东西...)
所以...
如果您实例化Demo类并调用$ demo-> myMethod(),您将获得一个控制台:该控制台可以访问第一个编写命令的方法,如:
> $this->myPublicMethod();
Run Code Online (Sandbox Code Playgroud)
但你无法成功运行第二个:
> $this->myPrivateMethod();
Run Code Online (Sandbox Code Playgroud)
你们有没有任何想法,或者是否有任何允许你这样做的PHP库?
非常感谢!
web*_*ave 57
只需将方法公之于众.但如果你想变得棘手,你可以尝试这个(PHP 5.3):
class LockedGate
{
private function open()
{
return 'how did you get in here?!!';
}
}
$object = new LockedGate();
$reflector = new ReflectionObject($object);
$method = $reflector->getMethod('open');
$method->setAccessible(true);
echo $method->invoke($object);
Run Code Online (Sandbox Code Playgroud)
Chr*_*ras 14
编辑: 更新以包含带参数的私有函数调用的示例.
从PHP 5.4开始,您可以使用预定义的Closure类将类的方法/属性绑定到甚至可以访问私有成员的delta函数.
例如,我们有一个带有私有变量的类,我们想要在类外部访问它:
class Foo {
private $bar = "Foo::Bar";
private function add_ab($a, $b) {
return $a + $b;
}
}
Run Code Online (Sandbox Code Playgroud)
PHP 5.4+
$foo = new Foo;
// Single variable example
$getFooBarCallback = function() {
return $this->bar;
};
$getFooBar = $getFooBarCallback->bindTo($foo, 'Foo');
echo $getFooBar(); // Prints Foo::Bar
// Function call with parameters example
$getFooAddABCallback = function() {
// As of PHP 5.6 we can use $this->fn(...func_get_args()) instead of call_user_func_array
return call_user_func_array(array($this, 'add_ab'), func_get_args());
};
$getFooAddAB = $getFooAddABCallback->bindTo($foo, 'Foo');
echo $getFooAddAB(33, 6); // Prints 39
Run Code Online (Sandbox Code Playgroud)
从PHP 7开始,您可以使用新Closure::call方法将对象的任何方法/属性绑定到回调函数,即使对于私有成员也是如此:
PHP 7+
$foo = new Foo;
// Single variable example
$getFooBar = function() {
return $this->bar;
};
echo $getFooBar->call($foo); // Prints Foo::Bar
// Function call with parameters example
$getFooAddAB = function() {
return $this->add_ab(...func_get_args());
};
echo $getFooAddAB->call($foo, 33, 6); // Prints 39
Run Code Online (Sandbox Code Playgroud)
您应该问的第一个问题是,如果您需要从类外部访问它,为什么将其声明为私有?如果这不是您的代码,那么发起者可能有充分的理由将其声明为私有,并且直接访问它是一种非常糟糕的(并且很大程度上无法维护的)做法。
编辑:正如 Adam V. 在评论中指出的那样,您需要在调用私有方法之前使其可访问。代码示例已更新以包含此内容。不过,我还没有测试过它 - 只是在此处添加以保持答案更新。
话虽如此,您可以使用反射来完成此任务。实例化ReflectionClass,调用getMethod您要调用的方法,然后调用invoke返回的ReflectionMethod.
代码示例(虽然我还没有测试过,所以可能有错误)可能看起来像
$demo = new Demo();
$reflection_class = new ReflectionClass("Demo");
$reflection_method = $reflection_class->getMethod("myPrivateMethod");
$reflection_method->setAccessible(true);
$result = $reflection_method->invoke($demo, NULL);
Run Code Online (Sandbox Code Playgroud)