Todos los intentos anteriores son básicamente defectuosa debido http://ocramius.github.io/presentations/proxy-pattern-in-php/#/71
Aquí está el ejemplo sencillo, tomado de mis diapositivas:
class BankAccount { /* ... */ }
Y aquí está nuestra "mala" lógica interceptor:
class PoorProxy {
public function __construct($wrapped) {
$this->wrapped = $wrapped;
}
public function __call($method, $args) {
return call_user_func_array(
$this->wrapped,
$args
);
}
}
Ahora si tenemos el siguiente método para llamar:
function pay(BankAccount $account) { /* ... */ }
Entonces esto no funcionará:
$account = new PoorProxy(new BankAccount());
pay($account); // KABOOM!
Esto se aplica a todas las soluciones que sugieren que aplican un "proxy".
Las soluciones que sugieren el uso explícito de otros métodos que luego llaman a su API interna son defectuosas, porque le obligan a cambiar su API pública para cambiar un comportamiento interno y reducen la seguridad de tipo.
La solución proporcionada por Kristoffer no tiene en cuenta public
métodos, que también es un problema, ya que no puede reescribir su API para que todo private
o protected
.
Aquí es una solución que resuelve este problema en parte:
class BankAccountProxy extends BankAccount {
public function __construct($wrapped) {
$this->wrapped = $wrapped;
}
public function doThings() { // inherited public method
$this->doOtherThingsOnMethodCall();
return $this->wrapped->doThings();
}
private function doOtherThingsOnMethodCall() { /**/ }
}
Aquí es cómo lo usa:
$account = new BankAccountProxy(new BankAccount());
pay($account); // WORKS!
Esta es una solución de tipo seguro, limpio, pero se trata de una mucha codificación, así que tómenlo solo como ejemplo.
Escribir este código repetitivo NO es divertido, por lo que es posible que desee utilizar diferentes enfoques.
para darle una idea de lo complicado de esta categoría de problemas está, sólo puede decirle que escribí an entire library para resolverlos, y algo más inteligente, más prudente, las personas mayores, incluso fue y se inventó un paradigma totalmente diferente, llamado "Aspect Oriented Programming" (AOP) .
Por tanto, propongo que investigue estas 3 soluciones que creo que puede ser capaz de resolver su problema de una manera mucho más limpia:
Uso ProxyManager 's 'access interceptor', que es básicamente un proxy tipo que le permite ejecutar un cierre cuando se llaman otros métodos (example). Aquí hay un ejemplo de cómo proxy de todas las llamadas a la API pública una $object
's:
use ProxyManager\Factory\AccessInterceptorValueHolderFactory;
function build_wrapper($object, callable $callOnMethod) {
return (new AccessInterceptorValueHolderFactory)
->createProxy(
$object,
array_map(
function() use ($callOnMethod) {
return $callOnMethod;
},
(new ReflectionClass($object))
->getMethods(ReflectionMethod::IS_PUBLIC)
)
);
}
continuación, sólo tiene que utilizar build_wrapper
como desee.
Utilice GO-AOP-PHP, que es una biblioteca de AOP real, completamente escrita en PHP, pero aplicará este tipo de lógica a TODAS las instancias de clases para las que defina cortes de punto. Esto puede ser o no lo que usted desea, y si su $callOnMethod
se debe aplicar solo para casos particulares, entonces AOP no es lo que está buscando.
Uso del PHP AOP Extension, que no creo ser una buena solución, sobre todo porque GO-AOP-PHP resuelve este problema de una manera más elegante/depurable, y porque las extensiones de PHP son inherentemente un desastre (que ha de ser atribuido a internos de PHP, no a los desarrolladores de extensiones). Además, al usar una extensión, la aplicación será lo menos portátil posible (intente convencer a un administrador de sistemas para que instale una versión compilada de PHP, si se atreve), y no podrá usar su aplicación en motores nuevos y geniales como HHVM.
En realidad, a) también puede tener los métodos como protegidos, simplemente no es público yb) no necesita el _ – ktolis
Tiene razón, protegido funcionará también, he eliminado el '_' en el ejemplo y hecho 'test3'' protected'. –
Debe 'return'in' __call' – Alex2php