Estou tendo um debate com um colega sobre o uso correto (se houver) trigger_error
no contexto de métodos mágicos . Em primeiro lugar, acho que isso trigger_error
deve ser evitado, exceto neste caso.
Digamos que temos uma classe com um método foo()
class A {
public function foo() {
echo 'bar';
}
}
Agora diga que queremos fornecer exatamente a mesma interface, mas use um método mágico para capturar todas as chamadas de método
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 as classes são iguais na maneira como respondem, foo()
mas diferem ao chamar um método inválido.
$a->doesntexist(); //Error
$b->doesntexist(); //Does nothing
Meu argumento é que métodos mágicos devem chamar trigger_error
quando um método desconhecido é capturado
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 as classes se comportem (quase) de forma 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
Meu caso de uso é uma implementação do ActiveRecord. Eu uso __call
para capturar e manipular métodos que essencialmente fazem a mesma coisa, mas têm modificadores como Distinct
or Ignore
, por exemplo
selectDistinct()
selectDistinctColumn($column, ..)
selectAll()
selectOne()
select()
ou
insert()
replace()
insertIgnore()
replaceIgnore()
Métodos como where()
, from()
, groupBy()
, etc. são codificados.
Meu argumento é destacado quando você liga acidentalmente insret()
. Se minha implementação de registro ativo codificasse todos os métodos, seria um erro.
Como em qualquer boa abstração, o usuário deve desconhecer os detalhes da implementação e confiar apenas na interface. Por que a implementação que usa métodos mágicos deve se comportar de maneira diferente? Ambos devem ser um erro.
fonte
4.something
?__call()
para fazer roteamento dinâmico, é realmente tão irracional esperar que em algum ponto da pista alguém possa querer lidar com o caso em que isso falha? De qualquer forma, isso está circulando, então esse será meu último comentário. Faça o que quiser, no final do dia, tudo se resume a um julgamento: Melhor suporte versus consistência. Ambos os métodos resultarão no mesmo efeito na aplicação no caso de nenhum tratamento especial.Vou lançar minha opinião opinativa por aí, mas se você usar em
trigger_error
qualquer lugar, estará fazendo algo errado. Exceções são o caminho a percorrer.Vantagens das exceções:
Resolvendo suas preocupações, chamar um método que não existe pode ser uma possibilidade válida . Isso depende inteiramente do contexto do código que você está escrevendo, mas há alguns casos em que isso pode acontecer. Dirigindo seu caso de uso exato, alguns servidores de banco de dados podem permitir algumas funcionalidades que outros não. Usar
try
/catch
e exceções em__call()
vs. uma função para verificar recursos é um argumento completamente diferente.O único caso de uso que posso pensar em usar
trigger_error
é paraE_USER_WARNING
ou mais baixo. Disparar um pensamentoE_USER_ERROR
é sempre um erro na minha opinião.fonte
trigger_error
no contexto de __call ou imita __callStatic o comportamento padrão da línguaNoMethodError
que você pode pegar se desejar. Erros são um erro gigante em PHP na minha opinião pessoal. Só porque o núcleo usa um método quebrado para relatar erros não significa que seu próprio código deveria.Erros PHP padrão devem ser considerados obsoletos. O PHP fornece uma classe interna ErrorException para converter erros, avisos e avisos em exceções com um rastreamento de pilha adequado completo. Você o usa assim:
Usando isso, essa questão se torna discutível. Os erros internos agora geram exceções e, portanto, seu próprio código também deve.
fonte
E_NOTICE
s em exceções. Isso seria ruim.IMO, este é um caso de uso perfeitamente válido para
trigger_error
:Usando essa estratégia, você obtém o
$errcontext
parâmetro se fizer$exception->getTrace()
dentro da funçãohandleException
. Isso é muito útil para determinados fins de depuração.Infelizmente, isso funciona apenas se você usar
trigger_error
diretamente do seu contexto, o que significa que não é possível usar uma função / método de invólucro para alias atrigger_error
função (portanto, você não pode fazer algo comofunction debug($code, $message) { return trigger_error($message, $code); }
se desejar os dados do contexto em seu rastreio).Eu estava procurando uma alternativa melhor, mas até agora não encontrei nenhuma.
fonte