Rufen Sie private Methoden und private Eigenschaften von außerhalb einer Klasse in PHP auf

Lesezeit: 9 Minuten

Ich möchte in sehr seltenen Einzelfällen von außerhalb der Klassen auf private Methoden und Variablen zugreifen.

Ich habe gesehen, dass dies nicht möglich ist, obwohl Introspektion verwendet wird.

Der Spezialfall ist der nächste:

Ich hätte gerne sowas:

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

Diese Methode sollte wie folgt in den Code eingefügt werden können:

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

(Dies ist nur eine Vereinfachung. Die echte geht durch einen Socket und implementiert eine Reihe weiterer Dinge …)

Damit…

Wenn Sie die Klasse Demo instanziieren und $demo->myMethod() aufrufen, erhalten Sie eine Konsole: Diese Konsole kann auf die erste Methode zugreifen und einen Befehl schreiben wie:

> $this->myPublicMethod();

Aber Sie können den zweiten nicht erfolgreich ausführen:

> $this->myPrivateMethod();

Hat jemand von euch eine Idee oder gibt es eine Bibliothek für PHP, mit der Sie dies tun können?

Vielen Dank!

  • Ähm … Wer würde jemals Methoden, die als privat gekennzeichnet sind, öffentlich zugänglich machen wollen? Ich meine … wenn Sie von außen darauf zugreifen müssen, verwenden Sie einfach public. Außerdem: Ihre Konsolenklasse ergibt keinen Sinn, wie Sie sie hier hinzugefügt haben. Es macht keinen einzigen Gebrauch von OOP und ist im Grunde nur eine Funktion, die in eine Klasse gezwungen wird.

    – Lamas

    29. April 2010 um 15:50 Uhr

  • FYI while(true) oder for(;;) sind etwas prägnantere und gebräuchlichere Schleifenmethoden bis zu einem expliziten break oder returnangetroffen wird.

    – mager

    29. April 2010 um 16:13 Uhr


  • @lamas: Wie ich bereits sagte, habe ich dies eher als POC als als echtes Beispiel getan. Die echte Console-Klasse hat mehr oder weniger etwa 1.000 Zeilen und erweitert einige andere durch Zusammensetzung. Die Wartbarkeit des Codes ist kein Problem, da er als isolierte Komponente außerhalb des Hauptprojekts, an dem wir arbeiten, verwendet wird, also nicht nur “eine Funktion, die in eine Klasse gezwungen wird”, sondern ein Auszug aus einer Klasse, die dies tut hier nicht gepostet werden, damit die Leute sich nicht ärgern. 🙂 @meagar: hehe, ich habe das while(TRUE != FALSE) aus Spaß gemacht, da PHP FALSE != 0 als FALSE validiert. trotzdem danke 😉

    – Pablo Lopez Torres

    29. April 2010 um 18:38 Uhr

  • @meagar: und ich habe vergessen, es zu kommentieren, ich habe nie eine Rückkehr oder eine Fortsetzung innerhalb einer Funktion geschrieben, es sei denn, es handelt sich um einen PoC. Ich denke, das ist keine gute Praxis und solche Dinge könnten die Lesbarkeit des Codes stören.

    – Pablo Lopez Torres

    29. April 2010 um 18:45 Uhr

  • @lamas: Ich stimme vollkommen mit dir überein Re: die Wahl des Umfangs. Aber ich stimme Ihnen nicht zu, dass eine Klasse keinen Sinn machen würde, wenn sie keinen einzigen OOP-Aufruf und rein statische Funktionen enthalten würde: Es ist eine Möglichkeit, eine Bibliothek aufzubauen und trotzdem davon zu profitieren von Autoloader-Funktionen, oder auch nur, um den Code sauberer zu machen, und fügen Sie eine Katalogisierungsebene für Ihre Funktionen hinzu.

    – Fabien Haddadi

    29. Oktober 2019 um 0:45 Uhr

Rufen Sie private Methoden und private Eigenschaften von auserhalb einer
webbiedave

Machen Sie die Methode einfach öffentlich. Aber wenn Sie knifflig werden wollen, können Sie dies versuchen (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);

  • das ist genau das, wonach ich gesucht habe. Ich verwende derzeit PHP 5.2.3 in der Entwicklungsumgebung, aber wir befinden uns im Migrationsprozess, das hilft mir sehr!! +1

    – Pablo Lopez Torres

    29. April 2010 um 18:40 Uhr

  • @webbiedave: Hm, ich habe auch die letzte Klasse LockedGate { private function __construct() {} … } und es scheint nicht zu funktionieren. Ich frage mich, ob “final” verhindert, dass die Zugänglichkeit geändert wird.

    – Dustin Graham

    23. Januar 2013 um 11:30 Uhr

  • @webbiedave: Ahh, ich denke, mein Problem war vielleicht, dass es eine statische Klasse war. Das hat bei mir funktioniert $method = $reflector->getMethod('myStaticPrivate'); $method->setAccessible(true); $method->invoke(NULL);

    – Dustin Graham

    23. Januar 2013 um 11:48 Uhr

  • Versuchen Sie dies mit PHP 5.3.22 auf der Shell $ php -a scheitert mit: PHP Fatal error: Call to private method LockedGate::open() from context '' in php shell code on line 1 PHP Stack trace: PHP 1. {main}() php shell code:0 Fatal error: Call to private method LockedGate::open() from context '' in php shell code on line 1 Call Stack: 5.3208 641904 1. {main}() php shell code:0

    – Rico Sonntag

    6. März 2013 um 7:47 Uhr


  • Ich habe den Reflexionscode aktualisiert. Meine primäre Antwort bleibt jedoch bestehen Machen Sie die Methode einfach öffentlich.

    – Webbiedave

    5. Oktober 2015 um 6:05 Uhr


1647138250 884 Rufen Sie private Methoden und private Eigenschaften von auserhalb einer
Christos Lytras

BEARBEITEN:
Aktualisiert, um Beispiele für private Funktionsaufrufe mit Parametern aufzunehmen.

Ab PHP5.4können Sie die vordefinierten verwenden Closure Klasse, um eine Methode/Eigenschaft einer Klasse an eine Delta-Funktion zu binden, die sogar Zugriff auf private Mitglieder hat.

Die Closure-Klasse

Zum Beispiel haben wir eine Klasse mit einer privaten Variablen und möchten außerhalb der Klasse darauf zugreifen:

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

PHP5.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

Ab PHP 7 können Sie die neue verwenden Closure::call Methode, um jede Methode/Eigenschaft eines Objekts an eine Callback-Funktion zu binden, auch für private Mitglieder:

PHP7+

$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

  • Abschnitt PHP 7+ ist großartig! Toll!

    – Nurbol Alpysbayev

    23. Mai 2018 um 6:08 Uhr

  • @NurbolAlpysbayev danke. Ich habe gerade festgestellt, dass die Antwort keinen Funktionsaufruf mit Parametern abdeckt, sondern nur private Variablen! Aktualisierte und hinzugefügte Beispiele für private Funktionsaufrufe für PHP 5.4+ und PHP 7+.

    – Christos Lytras

    23. Mai 2018 um 9:16 Uhr

  • Das funktioniert super! Aber denken Sie, dass dies die beste Vorgehensweise ist, da sie es wahrscheinlich aus einem bestimmten Grund privat gemacht haben?

    – David Jarrin

    19. Juni 2018 um 14:49 Uhr

  • @DavidJarrin Natürlich ist es das NICHT die beste Praxis. Dies sollte nach Möglichkeit vermieden werden; Es kann verwendet werden, wenn wir diesen Zugriff auf dieses private Mitglied haben möchten und 1) Wir wollen die Quelldateien der Klasse nicht ändern (vielleicht eine fertige Bibliothek, die nach dem Aktualisieren kaputt geht) und 2) Wenn es sich um eine der Klassen Ihres Projekts handelt, ändern Sie die Eigenschaft/Funktion in öffentlich oder erstellen Sie eine andere Funktion, um dieses private Element abzurufen.

    – Christos Lytras

    19. Juni 2018 um 15:05 Uhr


  • @ChristosLytras ja, das ist die Situation für mich, ich möchte die Bibliothek nicht wirklich ändern, weil sie beim Update kaputt geht, danke für die Antwort.

    – David Jarrin

    19. Juni 2018 um 17:58 Uhr

Rufen Sie private Methoden und private Eigenschaften von auserhalb einer
Dathan

Die erste Frage, die Sie stellen sollten, lautet: Wenn Sie von außerhalb der Klasse darauf zugreifen müssen, warum haben Sie es als privat deklariert? Wenn es nicht Ihr Code ist, hatte der Urheber wahrscheinlich einen guten Grund, ihn als privat zu deklarieren, und der direkte Zugriff darauf ist a sehr schlechte (und weitgehend unhaltbare) Praxis.

BEARBEITEN: Wie Adam V. in den Kommentaren betont, müssen Sie die private Methode zugänglich machen, bevor Sie sie aufrufen. Codebeispiel wurde aktualisiert, um dies einzuschließen. Ich habe es jedoch nicht getestet – nur hier hinzugefügt, um die Antwort auf dem neuesten Stand zu halten.

Davon abgesehen können Sie verwenden Betrachtung um das zu erreichen. Instanziieren ReflectionClassAnruf getMethod für die Methode, die Sie aufrufen möchten, und rufen Sie dann auf invoke auf dem Retournierten ReflectionMethod.

Ein Codebeispiel (obwohl ich es nicht getestet habe, daher können Fehler auftreten) könnte so aussehen

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

  • Dies sollte zu einer ReflectionException führen („Trying to invoke private method from scope ReflectionMethod“).

    – Webbiedave

    29. April 2010 um 16:06 Uhr

  • PHP-Reflection-API tut unterstützt das Aufrufen privater Methoden. Sie brauchen nur eine $reflection_method->setAccessible(true) nach dem $reflection_method = $reflection_class->getMethod("myPrivateMethod")

    – Adam v.

    4. Januar 2012 um 17:20 Uhr


Hier ist eine Variation der anderen Antworten, die verwendet werden können, um solche Anrufe auf einer Leitung zu tätigen:

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

Ich habe diese Probleme auch manchmal, aber ich umgehe sie durch meine Codierungsstandards. Private oder geschützte Funktionen werden mit einem vorangestellten Unterstrich gekennzeichnet, dh

private function _myPrivateMethod()

Dann mache ich die Funktion einfach öffentlich.

public function _myPrivateMethod()

Obwohl die Funktion öffentlich ist, gibt die Namenskonvention die Benachrichtigung, dass während öffentlich ist, privat ist und nicht wirklich verwendet werden sollte.

1647138251 104 Rufen Sie private Methoden und private Eigenschaften von auserhalb einer
Thomas Hünziker

Wenn Sie in der Klasse, in der die Methode definiert ist, eine Methode hinzufügen können, können Sie eine Methode hinzufügen, die intern call_user_method() verwendet. Dies funktioniert auch mit 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');

1647138252 797 Rufen Sie private Methoden und private Eigenschaften von auserhalb einer
Shiva Kiran

Die Antwort wird der Methode öffentlich zugänglich gemacht. Welchen Trick Sie auch immer machen werden, es wäre für andere Entwickler nicht verständlich. Zum Beispiel wissen sie nicht, dass bei einem anderen Code auf diese Funktion als öffentlich zugegriffen wurde, indem sie sich die Demo-Klasse ansehen.

Eine Sache noch. Diese Konsole kann auf die erste Methode zugreifen und einen Befehl schreiben wie:. Wie kann das überhaupt möglich sein? Die Konsole kann mit $this nicht auf Funktionen der Demoklasse zugreifen.

  • Ich denke, alle Leute hier, die das tun wollen, sind die “Mitentwickler” 🙂

    – beppe9000

    10. Mai 2019 um 20:22 Uhr

995690cookie-checkRufen Sie private Methoden und private Eigenschaften von außerhalb einer Klasse in PHP auf

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy