10 Stimmen

__call Äquivalent für öffentliche Methoden

Ich habe eine API zum Interagieren mit meiner Web-App, die durch eine Klasse definiert ist. Jede öffentlich zugängliche Methode muss eine Authentifizierung durchlaufen, bevor sie ausgeführt wird. Anstatt dieselbe Zeile in jeder Methode immer wieder zu schreiben, möchte ich die magische __call-Funktion verwenden. Es funktioniert jedoch nur bei privaten oder geschützten Methoden, und meine müssen öffentlich sein, um mit Zend_Json_Server zusammenzuarbeiten.

class MY_Api
{
  public function __call($name, $arguments)
  {
    // Hier befindet sich der Code, der die Argumente auf einen gültigen Authentifizierungstoken überprüft und einen Fehler zurückgibt, wenn falsch
  }

  public function myFunction($param1, $param2, $param3)
  {
    // Hier wird etwas gemacht, wenn der Benutzer die myFunction aufruft und die Parameter übergibt
    // Diese Funktion muss öffentlich bleiben, damit Zend_Json_Server sie analysieren kann
    // Aber ich möchte, dass sie von einer Zauberfunktion abgefangen wird, damit die Authentifizierung überprüft werden kann und das System abspringt, bevor es überhaupt zu dieser Funktion gelangt.
  }
}

Ist es möglich, in diese öffentlichen Funktionen einzugreifen und möglicherweise deren Ausführung abzubrechen, bevor sie aufgerufen werden?

0 Stimmen

Noch nicht. Ich war mir nicht sicher, ob es angemessen ist, es für diesen Abschnitt der Anwendung zu verwenden. Es handelt sich um eine REST-API, daher loggen sie sich nicht ein und richten keine Sitzungen ein, sondern übergeben stattdessen ein Token.

1 Stimmen

Was ruft die öffentliche Methode auf und kann dieser Aufrufer die Authentifizierungsmethode aufrufen?

0 Stimmen

@webbiedave Der Aufrufer ist die Methode Zend_Json_Server->handle(), daher müsste ich die Zend_Json_Server-Klasse erweitern, was für die Möglichkeit, dies tun zu können, überdimensioniert erscheint.

8voto

Jani Hartikainen Punkte 41573

__call funktioniert tatsächlich für alle Methoden, einschließlich öffentlicher Methoden. Der Grund, warum es nicht funktioniert, wenn die öffentliche Methode bereits existiert, ist, dass der Code außerhalb Ihrer Klasse bereits auf die öffentlichen Elemente zugreifen kann. __call wird nur für Elemente aufgerufen, auf die der Aufrufercode nicht zugreifen kann.

Soweit ich weiß, gibt es wirklich keine Optionen, um das zu tun, was Sie suchen, außer durch Verwendung einer Art von Dekorationsmuster:

class AuthDecorator {
    private $object;

    public function __construct($object) {
        $this->object = $object;
    }

    public function __call($method, $params) {
        //Setzen Sie hier den Code für den Zugriffscheck ein

        if($accessOk) {
            return call_user_func_array(array($this->object, $method), $params);
        }
    }
}

$api = new MY_Api();
$decoratedApi = new AuthDecorator($api);

//Alle Aufrufe an decoratedApi würden eine Authentifizierungsprüfung erhalten, und wenn sie erfolgreich ist, 
//zur Normalen Funktion in der Api-Klasse gelangen

0 Stimmen

Die Lösung hier ist klassisches Aspektorientiertes Programmieren mit einem Proxy und genau das, was du brauchst. Ich würde beanstanden, dass da __call() nur aufgerufen wird, wenn eine Methode nicht zugänglich ist und alle öffentlichen Methoden zugänglich sind, kann __call() als nicht funktionierend mit öffentlichen Methoden angesehen werden. Du hast mich begeistert, weil ich dachte, dass es vielleicht eine Schlupfloch geben könnte, das ich übersehen habe, aber leider war das nicht der Fall. :(

0 Stimmen

Oder Umbenennen aller Funktionen, um einen _ oder ähnliches zum Namen hinzuzufügen. Sie können die Methode x aufrufen, die durch __call gehen wird, und dann die öffentliche Methode x_ aufrufen wird. Jetzt denke ich darüber nach, dass ein Dekorateur wahrscheinlich einfacher wäre. :)

0 Stimmen

@David Harkness Ah, danke - Aspekte waren genau das andere, worüber ich sprechen wollte, aber ich konnte nur an Eigenschaften denken :) Aber ja, du hast vollkommen recht über __call aus dieser Perspektive.

3voto

webbiedave Punkte 47260

Da Sie meinen Kommentar als mögliche Lösung angesehen haben, habe ich ihn für die Nachwelt in eine Antwort formatiert:

Wenn aspektorientierte oder dekoratorische Lösungen nicht für Sie funktionieren, können Sie eine frameworkspezifischere Lösung ausprobieren, indem Sie den Authentifizierungscode entweder im Aufrufer Ihrer öffentlichen Methode oder sogar weiter oben platzieren.

1 Stimmen

Ich habe Zend_Json_Server noch nicht verwendet, aber sein Kusin Zend_Controller_Action definiert preDispatch(), das vor der tatsächlichen Aktionsmethode aufgerufen wird. Möglicherweise bietet das JSON-Komponente eine ähnliche Funktion.

0 Stimmen

Gute Idee, @David, aber Zend_Json_Server nicht und erweitert Zend_Server_Abstract, was auch nicht der Fall ist.

0 Stimmen

Vielen Dank für Ihre Antwort @webbiedave. Dies hat tatsächlich das Problem für diesen speziellen Fall gelöst.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X