2010-10-15 15 views
7

Tengo dos clases, "A" y "B". En la lógica de la aplicación, nadie tiene permitido crear un objeto de clase "B", a excepción de la clase "A". Pero, como no quiero tener las dos clases en el mismo archivo, no puedo restringirlo con la propiedad "privada".Restrinja lo que puede crear una clase PHP

¿Es posible crear este tipo de restricción? Si alguien que no sea "A" intenta crear un objeto de la clase "B", ¿dices cabrear?

+13

me interesa saber por qué usted quiere ¿hacer esto? – rojoca

Respuesta

0

En el constructor de B, requiere que A pase. Cuando desee obtener B de A, simplemente cree una B y pase A. Cuando se llama a una nueva B, se requerirá que A pase.

class A 
{ 
    private $b; 

    private function getB() 
    { 
     if (null === $this->b) 
     { 
      $this->b = new B($this); 
     } 

     return $this->b; 
    } 
} 

class B 
{ 
    public function __construct(A $a) 
    { 

    } 
} 
+1

Esto técnicamente podría ser engañado con '$ a = new A(); $ b = new B ($ a); '... – stevendesu

+0

En realidad, pensar en eso es lo correcto. Déjame probar lo que sucede si A sigue un patrón único. – MANCHUCK

+0

También podría clonar una instancia existente de B. Y dado que la clase será instanciada por aquellos que escriben el código de todos modos, no tiene mucho sentido restringir el acceso de esta manera. Las clases A y B también serán difíciles de probar de esta manera, ya que A tiene una dependencia codificada y B siempre requiere una A Mock. Hacer B un Singleton te arrojará al infierno por completo. OMI el valor que obtienes por restringir el acceso, no vale la pena. – Gordon

5

usted puede inspeccionar el trazado inverso:

class B 
{ 
    public function __construct() 
    { 
     $chain = debug_backtrace(); 
     $caller = $chain[1]['class']; 

     if ('A' != $caller) { 
      throw new Exception('Illegal instantiation'); 
     } 
    } 
} 
+4

Si realiza esta ruta, debe describir cómo funciona. La función se llama ** debug ** _backtrace por un motivo. – Gordon

+2

¡Oh, más de lo acordado Gordon, pero es una solución! –

7

Esto es tan hacky, ya que obtener de usted y no debe usarlo. Me único puesto, porque me gustan las cosas hacky;) Además, este generará un error si se ha habilitado el informe de errores E_STRICT:

class B 
{ 
    private function __construct() {} 

    public function getInstance() { 
     if (!isset($this) || !$this instanceof A) { 
      throw new LogicException('Construction of B from a class other than A is not permitted.'); 
     } 

     return new self; 
    } 
} 

class A 
{ 
    function someMethod() { 
     $b = B::getInstance(); // note that I'm calling the non-static method statically! 
    } 
} 

La razón por la que esto funciona es una "característica" que puede ser visto in the second example of this manual page.

+0

Tenga en cuenta que mientras esto funciona, hace que PHP escuche un 'E_STRICT'. – BoltClock

+0

Sí, ya lo digo en la primera oración;) – NikiC

+0

si alguien ** realmente ** quiere usar este hack, mejor habilita 'error_reporting (-1)' y usa '@ $ b = B :: getInstance() ; ', pero no estoy seguro si el' @ 'suprimirá todas las advertencias/errores generados en el método getInstance – Sudhi

0

Tal vez usted quiere usar algo como esto:

class A 
{ 
     protected function __construct() 
     { 
     } 
} 

class B extends A 
{ 
     public function __construct() 
     { 
       $a = new A(); 
     } 
} 

$b = new B(); 
-1

Uso get_called_class para saber qué clase intenta crear una instancia de un objeto:

class B 
{ 
     public function __construct() 
     { 
       if(get_called_class() != 'A') { 
        //booboo 
       } 
     } 
} 
+0

Esto solo funcionaría si' A' amplía 'B' y' B' se construyen, no 'A'. – NikiC

Cuestiones relacionadas