从 PHP 中的类外部调用私有方法和私有属性

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2738663/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 07:31:25  来源:igfitidea点击:

Call private methods and private properties from outside a class in PHP

phpvisibilityintrospection

提问by Pablo López Torres

I want to access private methods and variables from outside the classes in very rare specific cases.

在非常罕见的特定情况下,我想从类外部访问私有方法和变量。

I've seen that this is not be possible although introspection is used.

我已经看到尽管使用了自省,但这是不可能的。

The specific case is the next one:

具体案例如下:

I would like to have something like this:

我想要这样的东西:

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;
            }
        }
    }
}

This method should be able to be injected in the code like this:

这个方法应该能够像这样注入到代码中:

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()";
    }
}

(this is just one simplification. the real one goes through a socket, and implement a bunch of more things...)

(这只是一个简化。真正的通过一个套接字,并实现更多的东西......)

So...

所以...

If you instantiate the class Demo and you call $demo->myMethod(), you'll get a console: that console can access the first method writing a command like:

如果您实例化类 Demo 并调用 $demo->myMethod(),您将获得一个控制台:该控制台可以访问第一个方法,编写如下命令:

> $this->myPublicMethod();

But you cannot run successfully the second one:

但是你不能成功运行第二个:

> $this->myPrivateMethod();

Do any of you have any idea, or if there is any library for PHP that allows you to do this?

你们有没有任何想法,或者是否有任何 PHP 库允许您执行此操作?

Thanks a lot!

非常感谢!

回答by webbiedave

Just make the method public. But if you want to get tricky you can try this (PHP 5.3):

只需将方法公开即可。但如果你想变得棘手,你可以试试这个(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);

回答by Christos Lytras

EDIT:Updated to include examples of private function calls with parameters.

编辑:更新以包含带参数的私有函数调用的示例。

As of PHP 5.4, you can use the predefined Closureclass to bind a method/property of a class to a delta functions that has access even to private members.

PHP 5.4 开始,您可以使用预定义的Closure类将类的方法/属性绑定到甚至可以访问私有成员的增量函数。

The Closure class

闭包类

For example we have a class with a private variable and we want to access it outside the class:

例如,我们有一个带有私有变量的类,我们想在类外访问它:

class Foo {
    private $bar = "Foo::Bar";
    private function add_ab($a, $b) {
        return $a + $b;
    }
}

PHP 5.4+

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

As of PHP 7, you can use the new Closure::callmethod, to bind any method/property of an obect to a callback function, even for private members:

从 PHP 7 开始,您可以使用新Closure::call方法将对象的任何方法/属性绑定到回调函数,即使是私有成员:

PHP 7+

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

回答by Dathan

The first question you should ask is, if you need to access it from outside the class, why did you declare it private? If it's not your code, the originator probably had a good reason to declare it private, and accessing it directly is a verybad (and largely unmaintainable) practice.

您应该问的第一个问题是,如果您需要从类外部访问它,为什么要将其声明为私有?如果它不是您的代码,那么发起者可能有充分的理由将其声明为私有,而直接访问它是一种非常糟糕(并且在很大程度上无法维护)的做法。

EDIT: As Adam V. points out in the comments, you need to make the private method accessible before invoking it. Code sample updated to include this. I haven't tested it, though - just adding here to keep the answer updated.

编辑:正如 Adam V. 在评论中指出的那样,您需要在调用私有方法之前使其可访问。代码示例已更新以包含此内容。不过,我还没有对其进行测试 - 只是在此处添加以保持答案更新。

That having been said, you can use Reflectionto accomplish this. Instantiate ReflectionClass, call getMethodfor the method you want to invoke, and then call invokeon the returned ReflectionMethod.

话虽如此,您可以使用反射来完成此操作。实例化ReflectionClass,调用getMethod您要调用的方法,然后调用invoke返回的ReflectionMethod.

A code sample (though I haven't tested it, so there may be errors) might look like

代码示例(虽然我没有测试过,所以可能会有错误)可能看起来像

$demo = new Demo();
$reflection_class = new ReflectionClass("Demo");
$reflection_method = $reflection_class->getMethod("myPrivateMethod");
$reflection_method->setAccessible(true);
$result = $reflection_method->invoke($demo, NULL);

回答by Mark McEver

Here's a variation of the other answers that can be used to make such calls one line:

这是可用于在一行中进行此类调用的其他答案的变体:

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);
}

回答by buggedcom

I have these problems too sometimes, however I get around it through my coding standards. Private or protected functions are denoted with a prefix underscore ie

我有时也有这些问题,但是我通过我的编码标准来解决它。私有或受保护的函数用前缀下划线表示,即

private function _myPrivateMethod()

Then i simply make the function public.

然后我只是将功能公开。

public function _myPrivateMethod()

So although the function is public the naming convention gives the notification that whilst public is is private and shouldn't really be used.

因此,尽管该函数是公开的,但命名约定给出了通知,即 public 是私有的,不应真正使用。

回答by siva kiran

Answer is put public to the method. Whatever trick you are going to do it wouldn't be understandable to fellow developers. For example they do not know that at some other code this function has been accessed as public by looking at the Demo class.

答案是公开的方法。无论您要使用什么技巧,其他开发人员都无法理解。例如,他们不知道在其他一些代码中,通过查看 Demo 类,此函数已被作为公共访问。

One more thing. that console can access the first method writing a command like:. How can this even be possible? Console can not access demo class functions by using $this.

还有一件事。该控制台可以访问第一方法写入像一个命令:。这怎么可能?控制台无法使用 $this 访问演示类函数。

回答by seorch.me

I guess the reflectionClass is the only alternative if you really want to execute some private methods. Anyhow, if you just need read access to privat or protected properties, you could use this code:

如果你真的想执行一些私有方法,我想反射类是唯一的选择。无论如何,如果您只需要对私有或受保护的属性进行读取访问,您可以使用以下代码:

<?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)));

?>

回答by Thomas Hunziker

If you are able to added a method in the class where the method is defined, you can add method which uses the call_user_method() internally. This works also with PHP 5.2.x

如果您能够在定义方法的类中添加方法,则可以添加在内部使用 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');

回答by kobbycoder

Why dont you use protected? And extend it

你为什么不使用protected?并延长它