简体   繁体   English

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

[英]Call private methods and private properties from outside a class in PHP

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! 非常感谢!

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

EDIT: Updated to include examples of private function calls with parameters. 编辑:更新以包含带参数的私有函数调用的示例。

As of PHP 5.4 , you can use the predefined Closure class to bind a method/property of a class to a delta functions that has access even to private members. PHP 5.4开始 ,您可以使用预定义的Closure类将类的方法/属性绑定到甚至可以访问私有成员的delta函数。

The Closure class Closure类

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::call method, 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

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 very bad (and largely unmaintainable) practice. 如果它不是你的代码,那么发起人可能有充分的理由将其声明为私有,并且直接访问它是一种非常糟糕的(并且在很大程度上是不可维护的)实践。

EDIT : As Adam V. points out in the comments, you need to make the private method accessible before invoking it. 编辑 :正如Adam V.在评论中指出的那样,你需要在调用之前使私有方法可访问。 Code sample updated to include this. 更新代码示例以包含此内容。 I haven't tested it, though - just adding here to keep the answer updated. 我没有测试过它 - 只是在这里添加以保持答案更新。

That having been said, you can use Reflection to accomplish this. 话虽如此,你可以使用Reflection来实现这一目标。 Instantiate ReflectionClass , call getMethod for the method you want to invoke, and then call invoke on the returned ReflectionMethod . 实例化ReflectionClass ,为要调用的方法调用getMethod ,然后在返回的ReflectionMethod上调用invoke

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

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

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是私有的,不应该真正使用。

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访问演示类函数。

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. 如果能够在定义方法的类中添加方法,则可以添加在内部使用call_user_method()的方法。 This works also with PHP 5.2.x 这也适用于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');

Why dont you use protected? 你为什么不用保护? And extend it 并扩展它

I guess the reflectionClass is the only alternative if you really want to execute some private methods. 我想如果你真的想要执行一些私有方法,那么reflectionClass是唯一的选择。 Anyhow, if you just need read access to privat or protected properties, you could use this code: 无论如何,如果您只需要对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)));

?>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM