2009-06-11 7 views
6

J'ai un cas très spécial dans lequel j'ai besoin d'appeler une méthode protégée depuis l'extérieur d'une classe. Je suis très conscient de ce que je fais de la programmation, mais je ne serais pas entièrement opposé à le faire dans ce cas particulier que j'ai. Dans tous les autres cas, je dois continuer à interdire l'accès à la méthode interne, et je voudrais donc garder la méthode protégée.Appeler une méthode protégée depuis l'extérieur d'une classe en PHP

Quels sont les moyens élégants d'accéder à une méthode protégée en dehors d'une classe? Jusqu'à présent, j'ai trouvé this.

Je suppose qu'il est possible de créer une sorte de double instance agent de la classe cible qui sneakily l'accès aux ... internes

+0

Meilleure façon de le faire? Changez la fonction pour être publique. – Powerlord

Répondre

0

Je lance là-bas ce que j'ai pas programmé en PHP en deux ans. Pourriez-vous simplement ajouter une fonction à la classe qui appelle la méthode protégée comme ça?

$obj->publicFunc = create_function('$arg', 'return $this->protectedFunc($arg);'); 

Modifier: Je pense que Tom correct de regarder dans la documentation de create_function. Il semble que la portée de $ sera "fausse" quand vous essayez de l'appeler avec cet exemple.


Il ressemble à des fonctions anonymes traditionnelles sont pris en charge depuis PHP 5.3.0 aussi bien (et ma première solution ne fonctionnera probablement pas), donc je serais probablement écrire comme ceci:

$obj->publicFunc = function($arg) { 
    return $this->protectedFunc($arg); 
}; 

Depuis que je pense que cela semble un peu plus propre (et votre IDE de choix le mettra en évidence, bien sûr, bien sûr).


Ugh, j'essayé d'utiliser Reflection pour appeler la méthode, mais PHP ne vous permettra pas de le faire non plus. Il semble que vous allez devoir utiliser une sorte de classe d'enfant comme les autres affiches l'ont suggéré. Si vous trouvez une méthode qui fonctionne, les développeurs la classeront probablement comme un bug dans le futur et casseront votre code quand vous passerez à la prochaine version.

Je recommande d'étendre la classe.

+0

Nono, c'est un bon coup. Je vais probablement essayer. Si cela fonctionne, je vous le ferai savoir. –

+0

Je pense que cela créera simplement une chaîne $ obj-> publicFunc qui est le nom de la nouvelle fonction. Lorsque vous essayez de l'appeler, la portée est comme pour une fonction normale. –

+1

Je ne fonctionne pas: http://chadjohnson.ath.cx:8080/static/anonymous_function.phps. L'erreur que je reçois est "Appel à la méthode indéfinie Chad :: publicFunction()". Que pourrais-je faire de mal? –

1

Ceci est un peu kludgy, mais pourrait être une option.

Ajouter une classe enfant pour le plaisir d'accéder à votre fonction protégée

public class Child extends Parent { 
    public function protectedFunc() { 
     return parent::protectedFunc(); 
    } 
} 

Ensuite, instancier une instance de Child au lieu de Parent où vous devez appeler cette fonction.

+0

Hmm, oui, cela ressemble à ma seule option à ce stade. Peut-être que je devrais appeler cette classe Spy o_O. –

3

Je pense que dans ce cas, refactoring, donc vous n'avez pas besoin de ce genre de chose est probablement le moyen le plus élégant à faire. En disant qu'une option est d'utiliser __call et dans cette analyse debug_backtrace pour voir quelle classe a appelé la méthode. Ensuite, vérifiez un ami whitelst

class ProtectedClass { 

    // Friend list 
    private $friends = array('secret' => array('FriendClass')); 

    protected function secret($arg1, $arg2) { 
     // ... 
    } 

    public function __call($method, $args) { 

     $trace = debug_backtrace(); 
     $class = $trace[1]['class']; 
     if(in_array($class, $this->friends[$method])) 
      return $this->$method($args[0], $args[1]); 

     throw new Exception(); 
    } 
} 

Je pense que j'ai besoin d'une douche.

+0

Pourquoi ne pas simplement utiliser des reflets? – Smar

0

Je penserais à ce qui est la question avec la conception du programme si je dois appeler une fonction privée?

Il fut le cas lorsque

  • votre classe est responsable de plusieurs choses (il est vraiment deux ou thre calsses emballés ensemble) ou
  • les règles d'encapsulation sont brisées (fonctions d'utilité, pour exemple)

En trouvant une façon de marcher autour de cette question, vous serez nulle part plus près de la vraie solution.

+1

En général, c'est un bon conseil. Mais il existe parfois de bonnes raisons d'appeler des méthodes en dehors de leur périmètre défini. Par exemple, si vous ne voulez pas faire partie d'une méthode de votre API, mais que vous voulez l'appeler dans vos tests. Ou dans les vues CodeIgniter, vous pouvez vouloir que la fonction de hachage de votre mot de passe ne soit pas accessible depuis le Web, mais vous voulez les appeler dans vos tests. Contrairement à C++, PHP n'a pas de classes "friend" qui ont un accès privilégié aux internes de la classe. – qris

+1

Aussi si vous utilisez une API tierce qui n'expose pas la méthode, mais vous avez certainement besoin d'accéder à cette méthode. Certainement un point valide fait par Csaba, mais en de très rares occasions, vous devrez peut-être enfreindre les règles. –

-3

Supposons que votre déclaration de méthode va comme ceci:

protected function getTheFoo() { 
    ... 
} 

protected function setTheFoo($val) { 
    ... 
} 

Utilisation:

$obj->__get('the_foo'); 
$obj->__set('the_foo', 'myBar'); 

Cela permet de contourner les méthodes protégées et va directement droit aux variables d'instance.

+0

Je ne comprends pas. – Mateng

4

En PHP, vous pouvez le faire en utilisant Reflections. Pour appeler des méthodes protégées ou privées, utilisez la méthode setAccessible() http://php.net/reflectionmethod.setaccessible (il suffit de la définir sur TRUE)

+0

Vous devriez dire comment faire la chose comme une réponse, ne pas lier une autre réponse (dans ce cas, la documentation). Vous êtes cependant encouragés à créer un lien vers votre source et d'autres documents importants. – Smar

Questions connexes