Estoy teniendo un debate con un colega sobre el uso correcto (si lo hay) trigger_error
en el contexto de los métodos mágicos . En primer lugar, creo que trigger_error
debería evitarse a excepción de este caso.
Digamos que tenemos una clase con un método foo()
class A {
public function foo() {
echo 'bar';
}
}
Ahora digamos que queremos proporcionar exactamente la misma interfaz pero usar un método mágico para capturar todas las llamadas a métodos
class B {
public function __call($method, $args) {
switch (strtolower($method)) {
case 'foo':
echo 'bar';
break;
}
}
}
$a = new A;
$b = new B;
$a->foo(); //bar
$b->foo(); //bar
Ambas clases son iguales en la forma en que responden, foo()
pero difieren cuando se llama a un método no válido.
$a->doesntexist(); //Error
$b->doesntexist(); //Does nothing
Mi argumento es que los métodos mágicos deberían llamar trigger_error
cuando se detecta un método desconocido
class B {
public function __call($method, $args) {
switch (strtolower($method)) {
case 'foo':
echo 'bar';
break;
default:
$class = get_class($this);
$trace = debug_backtrace();
$file = $trace[0]['file'];
$line = $trace[0]['line'];
trigger_error("Call to undefined method $class::$method() in $file on line $line", E_USER_ERROR);
break;
}
}
}
Para que ambas clases se comporten (casi) de manera idéntica
$a->badMethod(); //Call to undefined method A::badMethod() in [..] on line 28
$b->badMethod(); //Call to undefined method B::badMethod() in [..] on line 32
Mi caso de uso es una implementación de ActiveRecord. Utilizo __call
para capturar y manejar métodos que esencialmente hacen lo mismo pero que tienen modificadores como Distinct
o Ignore
, por ejemplo
selectDistinct()
selectDistinctColumn($column, ..)
selectAll()
selectOne()
select()
o
insert()
replace()
insertIgnore()
replaceIgnore()
Métodos como where()
, from()
, groupBy()
, etc. están codificadas.
Mi argumento se resalta cuando accidentalmente llamas insret()
. Si mi implementación de registro activa codificara todos los métodos, sería un error.
Como con cualquier buena abstracción, el usuario debe desconocer los detalles de implementación y confiar únicamente en la interfaz. ¿Por qué la implementación que usa métodos mágicos debería comportarse de manera diferente? Ambos deberían ser un error.
fuente
4.something
?__call()
para hacer un enrutamiento dinámico, ¿es realmente tan irracional esperar que en algún lugar del camino alguien quiera manejar el caso donde eso falla? En cualquier caso, esto va en círculos, así que este será mi último comentario. Haga lo que quiera, al final del día, todo se reduce a una decisión: mejor soporte frente a consistencia. Ambos métodos tendrán el mismo efecto en la aplicación en el caso de que no haya un manejo especial.Voy a lanzar mi opinión obvia, pero si la usas en
trigger_error
cualquier lugar, entonces estás haciendo algo mal. Las excepciones son el camino a seguir.Ventajas de las excepciones:
Abordar sus inquietudes, llamar a un método que no existe puede ser una posibilidad válida . Esto depende completamente del contexto del código que está escribiendo, pero hay algunos casos en los que esto puede suceder. Al abordar su caso de uso exacto, algunos servidores de bases de datos pueden permitir alguna funcionalidad que otros no. Usar
try
/catch
y excepciones en__call()
vs. una función para verificar capacidades es un argumento completamente diferente.El único caso de uso que se me ocurre para usar
trigger_error
es paraE_USER_WARNING
o más bajo. Disparar un pensamientoE_USER_ERROR
es siempre un error en mi opinión.fuente
trigger_error
en el contexto de __call o __callStatic imita el comportamiento predeterminado del lenguajeNoMethodError
que puedes atrapar si lo deseas. Los errores son un error gigante en PHP en mi opinión personal. El hecho de que el núcleo utilice un método roto para informar errores no significa que su propio código deba hacerlo.Los errores estándar de PHP deben considerarse obsoletos. PHP proporciona una clase incorporada ErrorException para convertir errores, advertencias y avisos en excepciones con un seguimiento de pila completo y adecuado. Lo usas así:
Usando eso, esta pregunta se vuelve discutible. Los errores incorporados ahora generan excepciones, por lo que su propio código también debería hacerlo.
fuente
E_NOTICE
en excepciones. Eso sería malo.OMI, este es un caso de uso perfectamente válido para
trigger_error
:Usando esta estrategia, obtienes el
$errcontext
parámetro si lo haces$exception->getTrace()
dentro de la funciónhandleException
. Esto es muy útil para ciertos propósitos de depuración.Desafortunadamente, esto funciona solo si lo usa
trigger_error
directamente desde su contexto, lo que significa que no puede usar una función / método de envoltura para crear un alias de latrigger_error
función (por lo que no puede hacer algo comofunction debug($code, $message) { return trigger_error($message, $code); }
si desea los datos de contexto en su seguimiento).He estado buscando una mejor alternativa, pero hasta ahora no he encontrado ninguna.
fuente