我想在非常罕见的特定情况下从类外部访问私有方法和变量。
我已经看到尽管使用了内省,但这是不可能的。
具体案例是下一个:
我想有这样的事情:
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;
}
}
}
}
这个方法应该能够像这样注入代码:
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()";
}
}
(这只是一个简化。真正的一个通过套接字,并实现了一堆更多的东西......)
所以......
如果您实例化Demo类并调用$ demo-> myMethod(),您将获得一个控制台:该控制台可以访问第一个编写命令的方法,如:
> $this->myPublicMethod();
但是你不能成功地运行第二个:
> $this->myPrivateMethod();
您是否有任何想法,或者是否有任何允许您这样做的PHP库?
非常感谢!
答案 0 :(得分:52)
只需将方法设为公开。但是如果你想变得棘手,你可以试试这个(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);
答案 1 :(得分:11)
修改强> 更新为包含带参数的私有函数调用的示例。
从 PHP 5.4 开始,您可以使用预定义的Closure
类将类的方法/属性绑定到甚至可以访问私有成员的delta函数。
例如,我们有一个带有私有变量的类,我们想在类外部访问它:
class Foo {
private $bar = "Foo::Bar";
private function add_ab($a, $b) {
return $a + $b;
}
}
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
从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
答案 2 :(得分:4)
您应该问的第一个问题是,如果您需要从课外访问它,为什么要将其声明为私有?如果它不是你的代码,那么发起人可能有充分的理由将其声明为私有,并且直接访问它是非常坏(并且在很大程度上不可维护)的做法。
编辑:正如Adam V.在评论中指出的那样,您需要在调用私有方法之前使其可访问。更新代码示例以包含此内容。我没有测试过它 - 只是在这里添加以更新答案。
据说,您可以使用Reflection来完成此任务。实例化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);
答案 3 :(得分:3)
以下是其他答案的变体,可用于将此类调用换成一行:
public function callPrivateMethod($object, $methodName)
{
$reflectionClass = new \ReflectionClass($object);
$reflectionMethod = $reflectionClass->getMethod($methodName);
$reflectionMethod->setAccessible(true);
$params = array_slice(func_get_args(), 2); //get all the parameters after $methodName
return $reflectionMethod->invokeArgs($object, $params);
}
答案 4 :(得分:2)
我有时会遇到这些问题,但是我通过编码标准解决了这个问题。私有或受保护的函数用前缀下划线表示,即
private function _myPrivateMethod()
然后我简单地将该功能公之于众。
public function _myPrivateMethod()
因此,尽管该函数是公共的,但命名约定会给出通知,即public是私有的,不应该真正使用。
答案 5 :(得分:1)
将答案公之于众。无论你打算做什么伎俩都不会让其他开发人员理解。例如,他们不知道在其他一些代码中,通过查看Demo类,该函数已被公开访问。
还有一件事。 控制台可以访问第一个编写命令的方法,如: 。这怎么可能呢?控制台无法使用$ this访问演示类函数。
答案 6 :(得分:0)
我想如果你真的想要执行一些私有方法,那么reflectionClass是唯一的选择。无论如何,如果您只需要对privat或受保护属性的读访问权限,则可以使用以下代码:
<?php
class Demo
{
private $foo = "bar";
}
$demo = new Demo();
// Will return an object with public, private and protected properties in public scope.
$properties = json_decode(preg_replace('/\\\\u([0-9a-f]{4})|'.get_class($demo).'/i', '', json_encode((array) $demo)));
?>
答案 7 :(得分:0)
如果能够在定义方法的类中添加方法,则可以添加在内部使用call_user_method()的方法。这也适用于PHP 5.2.x
<?php
class SomeClass {
public function callprivate($methodName) {
call_user_method(array($this, $methodName));
}
private function somePrivateMethod() {
echo 'test';
}
}
$object = new SomeClass();
$object->callprivate('somePrivateMethod');
答案 8 :(得分:0)
为什么不使用受保护的?并扩展它
答案 9 :(得分:-1)
<?php
$request="email";
$data=[1,2,3,4,5];
$name=new Update($request,$data);
class Update{
private $request;
private $data;
function __construct($request,$data){
$this->request=$request;
$this->data=$data;
if($this->request=='email'){
$this->update_email();
}
else{
echo "Can't do anything";
}
}
private function update_email(){
echo $this->request;
echo '\n';
foreach($this->data as $x){
echo $x."\n";
}
}
}
?>