2008-11-25 15 views
28

¿Hay algún equivalente de "amigo" o "interno" en php? Si no, ¿hay algún patrón a seguir para lograr este comportamiento?PHP equivalente de amigo o interno

Edit: Disculpa, pero el estándar Php no es lo que estoy buscando. Estoy buscando algo en la línea de lo que hizo el maestro de ceremonias.

Tengo clases que están haciendo llamadas al sistema estilo C en la parte de atrás y el malabarismo ha comenzado a ser engorroso. Tengo funciones en el objeto A que toman el objeto B como un parámetro y tienen que llamar a un método en el objeto B que pasa en sí mismo como argumento. El usuario final podría llamar al método en B y el sistema se derrumbaría.

Respuesta

40

PHP no soporta ningún amigo declaraciones similares. Es posible simular esto usando los métodos __get y __set de PHP5 e inspeccionando una traza inversa solo para las clases de amigos permitidas, aunque el código para hacerlo es un poco torpe.

Hay un poco de sample code y la discusión sobre el tema en el sitio de PHP:

class HasFriends 
{ 
    private $__friends = array('MyFriend', 'OtherFriend'); 

    public function __get($key) 
    { 
     $trace = debug_backtrace(); 
     if(isset($trace[1]['class']) && in_array($trace[1]['class'], $this->__friends)) { 
      return $this->$key; 
     } 

     // normal __get() code here 

     trigger_error('Cannot access private property ' . __CLASS__ . '::$' . $key, E_USER_ERROR); 
    } 

    public function __set($key, $value) 
    { 
     $trace = debug_backtrace(); 
     if(isset($trace[1]['class']) && in_array($trace[1]['class'], $this->__friends)) { 
      return $this->$key = $value; 
     } 

     // normal __set() code here 

     trigger_error('Cannot access private property ' . __CLASS__ . '::$' . $key, E_USER_ERROR); 
    } 
} 

(Código demostrado por tsteiner en nerdclub red del punto on bugs.php.net)

+15

¡Este es un hack precioso! Me encanta y me repugna. Inteligente sin embargo. +1 –

+1

¿Cómo es el rendimiento con esto? ¿Es un golpe notable? Esto realmente sería exactamente lo que estoy buscando. – smack0007

+0

Esto es perfecto para la encapsulación. Ahora tengo una clase principal sin getters, un Accesor que implementa getters y View que es el único que puede usar getters. +100 si pudiera –

-13

Estoy bastante seguro de que lo que está buscando es "protegido" o "privado", dependiendo de su caso de uso.

Si está definiendo una función en una clase, y sólo desea que esté disponible a sí mismo, se le define de esta manera:

private function foo($arg1, $arg2) { /*function stuff goes here */ } 

Si está definiendo una función en una clase que desea estar disponible para clases que heredan de esta clase, pero no está disponible públicamente, definida de esta manera:

protected function foo($arg1, $arg2) 

estoy bastante seguro de que por defecto en PHP5, funciones son públicas, lo que significa que no lo hace tiene que usar la siguiente sintaxis, pero es opcional:

public function foo($arg1, $arg2) { /*function stuff goes here */ } 

Aún tendrá que crear una instancia del objeto antes de usar una función pública. Así que sólo voy a ser exhaustivo y hacerle saber que con el fin de utilizar una función en una clase sin crear instancias de un objeto, asegúrese de utilizar la siguiente sintaxis:

static function foo($arg1, $arg2) { /*function stuff goes here */ } 

que le permitirá utilizar la función de sólo se hace referencia a la clase, de la siguiente manera:

MyClass::foo($a1, $a2); 

de lo contrario, tendrá que hacer lo siguiente:

$myObject = new MyClass(); 
$myObject->foo($a1, $a2); 
+2

creo que lo que el PO estaba pidiendo era cómo implementar en PHP algo similar a la 'palabra clave friend' en C++, es decir, hacer ciertos/datos protegidos/métodos privados disponibles _Para ciertas clases que hicieron no heredar de it_. – Xenon

5

También es posible elevar los privilegios, fugas de alias de datos de forma selectiva , usando un apretón de manos y cierres en php> = 5.3.3.

Básicamente, la interacción es válida: la clase A tiene un método público que acepta un objeto de clase B y llama a B-> grantAccess (o lo que sea que defina su interfaz), pasándole un cierre. El cierre use($that,$anythingelseyouneed) donde $ that = $ this, y cualquier otra cosa que necesite para determinar a qué propiedades se les permite acceder. El cierre tiene un argumento: la propiedad de regresar; si es una propiedad en $ que y todo está bien, el cierre devuelve la propiedad.De lo contrario, devuelve '', o arroja una excepción, o tal vez un valor predeterminado.

Clase B-> grantAccess acepta un llamativo y lo almacena, usándolo en otros métodos para arrancar propiedades privadas, el cierre permite ser filtrado. Haga que el constructor predeterminado de la clase B sea privado. Construya una B usando un método de fábrica estático que tome un argumento Clase A, para garantizar que se produzca el intercambio de información.

Gist aquí: https://gist.github.com/mcamiano/00592fb400e5043d8acd