2009-06-11 4 views
6

Ho un caso molto particolare in cui ho bisogno di chiamare un metodo protetto dall'esterno di una classe. Sono molto consapevole di ciò che faccio in modo programmatico, ma non sarei del tutto contrario a farlo in questo caso speciale che ho. In tutti gli altri casi, ho bisogno di continuare a negare l'accesso al metodo interno e quindi vorrei mantenere il metodo protetto.Chiamare un metodo protetto dall'esterno di una classe in PHP

Quali sono alcuni eleganti modi per accedere a un metodo protetto al di fuori di una classe? Finora, ho trovato this.

Suppongo che potrebbe essere possibile creare una sorta di esempio doppio agente della classe di destinazione che avrebbe subdolamente fornire l'accesso alle parti interne ...

+0

Il modo migliore per farlo? Cambia la funzione in modo che sia pubblica. – Powerlord

risposta

0

Sto solo buttando questa là fuori visto che non ho programmato in PHP in due anni. Potresti semplicemente aggiungere una funzione alla classe che chiama il metodo protetto in questo modo?

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

Edit: Penso di Tom corretto nel guardare la documentazione per create_function. Sembra che lo scopo di $ sia "sbagliato" quando si tenta di chiamarlo con questo esempio.


Sembra tradizionali funzioni anonime sono supportati da PHP 5.3.0, nonché (e la mia prima soluzione probabilmente non funzionerà), così probabilmente sarei scriverlo come questo, invece:

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

Dal momento che penso che sembra un po 'più pulito (e il tuo IDE di scelta lo evidenzierà ovviamente meglio).


Ugh, ho provato ad utilizzare Reflection per chiamare il metodo, ma PHP non vi permetterà di fare nemmeno questo. Sembra che dovrai usare una sorta di classe per bambini come suggerito dagli altri poster. Se trovi un metodo che funziona, gli sviluppatori lo classificheranno come un bug in futuro e interromperanno il codice quando eseguirai l'aggiornamento alla versione successiva.

Raccomando di estendere la classe.

+0

Nono, è un buon colpo. Probabilmente la proverò. Se funziona, ti farò sapere. –

+0

Penso che questo creerà solo una stringa $ obj-> publicFunc che è il nome della nuova funzione. Quando provi a chiamarlo lo scope è come per una funzione normale. –

+1

Non riesco a farlo funzionare: http://chadjohnson.ath.cx:8080/static/anonymous_function.phps. L'errore che ottengo è "Chiama al metodo non definito Chad :: publicFunction()." Cosa potrei fare di sbagliato? –

1

Questo è un po 'cauto, ma potrebbe essere un'opzione.

Aggiungere una classe figlia per il gusto di accesso al tuo funzione protetta

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

Poi, istanziare un'istanza di Child invece di Parent in cui è necessario chiamare tale funzione.

+0

Hmm, sì, questa sembra la mia unica opzione a questo punto. Forse dovrei chiamare questa classe Spia o_O. –

3

Vorrei pensare che in questo caso, il refactoring in modo da non si richiede questo genere di cose è probabilmente la più elegante strada da percorrere. Nel dire che un'opzione è usare __call e all'interno di quella analisi debug_backtrace per vedere quale classe ha chiamato il metodo. Quindi controlla un amico

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

Penso di aver bisogno di una doccia.

+0

Perché non usare solo i riflessi? – Smar

0

che ci avrei pensato che cosa è la questione con la progettazione del programma se devo chiamare una funzione privata?

ha usato per essere il caso quando

  • tua classe è responsabile di molte cose (è davvero due o Thre calsses avvolti insieme) o
  • le regole di incapsulamento sono rotti (funzioni di utilità, per esempio)

trovando alcun modo per andare in giro questa domanda, sarete in nessun posto più vicino alla vera soluzione.

+1

In generale questo è un buon consiglio. Ma a volte ci sono buone ragioni per chiamare metodi al di fuori del loro ambito definito. Ad esempio, se non vuoi rendere un metodo parte della tua API, ma vuoi chiamarlo nei tuoi test. Oppure nelle visualizzazioni CodeIgniter, potresti desiderare che la funzione di hash della password non sia richiamabile dal Web, ma devi chiamarli nei test. A differenza di C++, PHP non ha classi "amiche" che hanno accesso privilegiato alle classi interne. – qris

+1

Anche se stai usando API di terze parti che non espongono il metodo, ma sicuramente hai bisogno di accedere a quel metodo. Sicuramente un punto valido fatto da Csaba, ma in rare occasioni, potresti dover violare le regole. –

-3

Supponiamo che la vostra dichiarazione di metodo va in questo modo:

protected function getTheFoo() { 
    ... 
} 

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

Usage:

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

Questo bypassa i metodi protette e va direttamente direttamente alle variabili di istanza.

+0

Non ho capito. – Mateng

4

In PHP è possibile farlo utilizzando Reflections. Per invocare metodi protetti o privati ​​utilizzare il metodo setAccessible() http://php.net/reflectionmethod.setaccessible (impostarlo su TRUE)

+0

Si dovrebbe dire come fare la cosa come risposta, non per collegare qualche altra risposta (in questo caso, la documentazione). Siete, tuttavia, incoraggiati a collegarvi alla vostra fonte e ad altri importanti pezzi di documentazione. – Smar