PHP DO BÁSICO AO AVANÇADO – AULA 21 – Outras mudanças de comportamento, logs e registros de erros e usos

Tempo de Leitura: 34 Minutos

Para dar continuidade as extensões, hoje vamos falar de outras extensões que modificam a forma com que o PHP manipula dados, excessões e que também afetam o seu comportamento padrão. Estas extensões também são baseadas na PECL e podem ser baixadas e instaladas, ou compiladas junto com o PHP tornando-as como parte dele. O uso dessas extensões pode facilitar muito ao desenvolvedor, pois adicionam recursos como manipulações de novos tipos de dados, checagem de tipos de dados, manipulação e recuperação de erros em tempo de execução e formas diferenciadas de lidar com erros, objetos e exceções. Vamos lá, para mais essa aula para entender melhor esses conceitos mais avançados e que podem fazer muita diferença em termos de qualidade de código e performance da sua aplicação.

Componere ou Compose – Não confundir com COMPOSER que será abordado em outro momento

Note, que esta extensão possui um nome parecido com um outro componente ou acessório muito comum do PHP e que vem ganhando espaço, por ser um componente mais eficiente para o gerenciamento de dependências e de importações de códigos e objetos de terceiros chamado COMPOSER que imos na aula 20, porém, vai receber mais atenção, por ser atualmente de extrema importância principalmente em projetos onde podemos depender de bibliotecas específicas de código de terceiros. Portanto, não confunda a COMPOSE/COMPONERE com o software COMPOSER pois são coisas totalmente diferentes.

Esta extensão, visa criar em ambientes de produção uma API para a manipulação de Classes, extensão e manipulação delas. Essa extensão funciona tanto em distribuições baseadas em Windows como em Linux e pode ser instalada por meio da PECL com o comando:

pecl install componere

É dividida em 4 grupos de funções, a saber, Componere\Abstract\Definition que é estrutura da Classe, e que define a Interface, os Métodos, os Tratamentos e as Reflexões. A Componere\Definition que é a base de construção da classe, e trata de toda a parte responsável pelo registro dos componentes, definições e extensão dos objetos. A Componere\Patch que faz toda a parte do tratamento e aplicação de Patch a classes existentes. A Componere\Method responsável pelos Métodos e permite acessa-los e modifica-los em tempo de execução. Componere\Value que faz a parte de manipulação e encapsulamento dos valores e controla a acessibilidade destes. Vamos estudar um pouco mais sobre eles agora.

public Componere\Abstract\Definition::addInterface(string $interface): Definition – Deve implementar a interface fornecida na definição atual, a $interface não diferencia maiúsculas e minúsculas e o valor retornado é a DEFINITION atual da interface.

public Componere\Abstract\Definition::addMethod(string $name, Componere\Method $method): Definition – Cria ou substitui um método da definição atual, onde o $name é o nome da interface, e o $method é o componente ou método que não pode ter sido adicionado anteriormente. Pode retornar uma exceção se o método já tiver sido adicionado, ou se a interface não existir.

public Componere\Abstract\Definition::addTrait(string $trait): Definition – Deve usar o $trait fornecido para a definition atual.  Adicionar uma Trait é uma maneira eficiente de estender uma classe “final”, substituindo métodos e adicionando novos, sem ter que adicionar individualmente cada método como um encerramento. Também resultando em um código mais legível.

public Componere\Abstract\Definition::getReflector(): ReflectionClass – Deve criar ou retornar um ReflectionClass, retornando a definição atual armazenada em cache.

A classe Definition permite ao programador construir e registrar um tipo em tempo de execução. Se uma Definição substituir uma classe existente, a classe existente será restaurada quando a Definição for destruída. Às vezes, podemos desejar estender uma classe de terceiros que foi definida como “final” com uso dessa classe, a classe a filho resultante estenderá uma classe  definida como “final”, adicionando um método, uma instância de objeto será capaz de acessar membros pais e é reconhecida como uma instância tanto da classe filha criada dinamicamente quanto de sua classe pai. Suas definições são:

public Componere\Definition::__construct(string $name, string $parent, array $interfaces) – Onde $name é o nome da classe, $parent (opcional) é o nome de outra classe ou instância, $interface (opcional) é o nome das classes ou interfaces referenciadas pela instrução, pode ser um array contendo diversas interfaces em uma única chamada. Pode lançar excessão se a classe a ser substituida inteiramente, ou se não forem encontradas.

public Componere\Definition::addConstant(string $name, Componere\Value $value): Definition – Deve declarar uma constante de classe na definição atual.

public Componere\Definition::addProperty(string $name, Componere\Value $value): Definition – Deve declarar uma propriedade de classe na definição atual

public Componere\Definition::register(): void – Deve registrar a definição atual.

public Componere\Definition::isRegistered(): bool – Deve detectar o estado de registro desta Definition.

public Componere\Definition::getClosure(string $name): Closure – Deve retornar um Closure para o método especificado pelo nome.

public Componere\Definition::getClosures(): array – Retorna um array de Closures para o escopo atual.

A classe Patch permite ao programador alterar o tipo de uma instância em tempo de execução sem registrar uma nova definition quando um Patch é destruído, ele é revertido, de forma que as instâncias que foram corrigidas ou alteradas durante o tempo de vida do patch sejam restauradas ao seu tipo formal.

public Componere\Patch::__construct(object $instance, array $interfaces) – Onde $instance é o Alvo para o Patch ser aplicado, e $interfaces é um array de nomes de interfaces que serão afetadas, e é opcional.

public Componere\Patch::apply(): void – Aplica o Pach corrente.

public Componere\Patch::revert(): void – Reverte a aplicação do Patch.

public Componere\Patch::isApplied(): bool – Detecta o estado do Pacth TRUE de aplicado, FALSE se não aplicado.

public Componere\Patch::derive(object $instance): Patch – Deriva um patch da instancia fornecida.

public Componere\Patch::getClosure(string $name): Closure – Retorna a Closure para o método especificado em $name.

public Componere\Patch::getClosures(): array – Devolve todas as Closures para o patch atual.

Um método representa uma função com sinalizadores de acessibilidade modificáveis, Itens declarados como públicos podem ser acessados de qualquer lugar. Membros declarados como protegidos só podem ser acessados na classe declarante e suas classes herdeiras. Membros declarados como privados só podem ser acessados na classe que define o membro privado. Métodos sem qualquer declaração explícita serão definidos como públicos por padrão em PHP.

public Componere\Method::__construct(Closure $closure) – Basta indicar o nome da Clojure

public Componere\Method::setPrivate(): Method – Muda a acessibilidade do método, setando-o como privado.

public Componere\Method::setProtected(): Method – Muda a acessibilidade tornando-o protegido.

public Componere\Method::setStatic(): Method – Muda a acessibilidade tornando o método Estático.

public Componere\Method::getReflector(): ReflectionMethod – Retorna a reflexão do método atual.

A classe Valor representa uma variável PHP de todos os tipos, incluindo o tipo indefinido (void). E também pode ser modificada pela extensão Componere, veja:

public Componere\Value::__construct( $default = ?) – Define o valor padrão passado, ou dispara uma exceção de alerta caso o valor não seja aceitável.

public Componere\Value::setPrivate(): Value – Seta a acessibilidade do Value como privado.

public Componere\Value::setProtected(): Value – Seta a visibilidade do value como Protegido.

public Componere\Value::setStatic(): Value – Seta a visibilidade como Estática.

public Componere\Value::isPrivate(): bool – Verifica se o valor é Privado, e retorna True ou False.

public Componere\Value::isProtected(): bool – Verifica se é Protegido e retorna true ou false.

public Componere\Value::isStatic(): bool – Verifica se o valor é Estatico e retorna true ou false.

public Componere\Value::hasDefault(): bool – Retorna true caso exista um valor, false caso não exista.

Componere\cast(Type $type, $object): Type – Define um novo TIPO para o Objeto.

Componere\cast_by_ref(Type $type, $object): Type –  Define o novo tipo para o objeto, usando a referência ao objeto original.

OBSERVAÇÕES IMPORTANTES

Estou citando essas funções neste ponto do curso, pois é importante para quem está acompanhando saber que existem extensões, que permitem um maior controle e alteração de métodos já instanciados e definidos, o que em até certo ponto estende a compatibilidade com OOP por parte do PHP, e também, viola algumas convenções mais rídidas e doutrinas da OOP. No meu ponto de vista, a linguagem PHP somente em sua versão 8.0 passou a ter melhor aderência a alguns padrões da Orientação a Objetos, porém, como programador não vejo o uso correto da OOP em algo que possa ser melhor aplicado e escrito em PHP.

Na minha opinião, a linguagem vem evoluindo no suporte a OOP, porém, existem linguagens muito mais propicias a implementações totalmente baseadas em Objetos como o Java, ou mesmo o .Net resolvi apresentar esta extensão, por fazer parte, da linguagem e estar coberta pelo escopo deste curso, porém, desencorajaria qualquer uso do PHP para desenvolvimento de aplicações totalmente dentro das diretrizes e boas práticas da OOP. É função do desenvolvedor ou do Led Técnico de um projeto, identificar qual é a melhor abordagem e qual é o melhor uso de cada uma das ferramentas e das metodologias de desenvolvimento.

PHP é uma linguagem fantástica e extremamente poderosa para lidar com solicitações HTTP em diversas instâncias, e até mesmo, para tratamento de conexões em sockets, possui suporte a OOP porém, devido até mesmo as características das aplicações e a aplicabilidade da linguagem (nicho de mercado), não vejo nenhuma necessidade de evoluir no sentido de manter maior aderência as regras da OOP, portanto, se o requisito do projeto mostrar que o suporte total a OOP é necessário, e o rígido controle de tipos e visibilidade de métodos for necessária, linguagens como JAVA e .NET possui maior aderência, e devem ser estudadas como alternativa ao uso do PHP.

Como o objetivo do curso é ser DO BÁSICO AO AVANÇADO e cobrir totalmente a utilização da linguagem, me senti obrigado a exemplificar e dar mesmo que de maneira superficial uma visão desta extensão. Da mesma maneira que veremos em uma etapa mais avançada do curso outros usos da OOP utilizando o PHP, porém, não recomendo pelo menos em sua versão atual PHP 8.0 o uso do PHP para definições que violem sua base, que é justamente a mutabilidade e a tipagem fraca, essas são características das linguagens e também da WEB, veja as próprias definições dos cabeçalhos e protocolos de comunicação utilizados em mais de 85% de todas as transações voltadas a web e seus afins como aplicação em redes locais e intercomunicação. Espero em uma próxima aula, abordar o tipo de aplicações que tem maior aderência ao uso de PHP como linguagem principal, e quais as expectativas que devemos ter em relação a isso, dando ao desenvolvedor um escopo de uso.

Manipulação LOG DE ERROS, LOG DE ACESSO e ERROS DE EXECUÇÃO E DISPONIBILIDADE

A manipulação de erros, permite ao programador definir a suas próprias regras para o manuseio e exibição ou tratamento de erros, assim como permitem modificar a maneira com que é efetuado o log de erros, e de acessos, isso, permite um melhor controle e adaptação as necessidades do sistema em execução ou aos recursos do servidor permitindo controle de como o seu software (script) vai se portar, trazendo notificações coerentes, dentro do formato esperado pelo usuário e podendo reportar e disparar ativamente alertas de instabilidade ou de  os avisos de erro para os responsáveis pelo sistema e pela operação dos servidores.

Com as funções de log, você pode mandar mensagens diretamente para outras máquinas, para um email (ou mesmo para um celular ou smartphone), para os logs do sistema hospedeiro, etc, assim você pode seletivamente logar e monitorar as partes mais importantes das suas aplicações e websites, visando total controle de tarefas e automações. Tenha em mente aqui, que um script PHP pde não somente ser usado pelo usuário final do sistema, como também pode ser utilizado pelos Administradores do Sistema, por exemplo para tarefas e operações agendas (CRON), rodando rotinas internas, ou necessárias em determinados períodos. Veja um exemplo de um sistema que precise gerar relatórios de movimentos do dia anterior em PDF e que consomem mais recursos do servidor, e a tarefa pode simplesmente ser agendada pela cron do SO para rodar em horários de menor movimento, rotinas que dependem de acesso a servidores externos, que podem estar passando por indisponibilidade podem notificar os administradores dos sistemas de maneira automática sobre a ausência de um recurso, ao mesmo tempo em que apresentam uma mensagem amigável ao usuário, ou usam dados do cache do sistema. Estes são só alguns cenários onde rotinas de manipulação e tratamento de erros são de extrema importância.

As funções de erro permitem você configurar quais níveis de erro devem ser reportados, como e onde eles serão reportados e o tipo de resposta que será dado, indo desde simples avisos até as funções retornadas durante os erros, e mesmo ações que possam ser demandadas em outros sistemas como bancos de dados, ou mesmo sockets abertos de comunicações com outros sistemas e servidores. O PHP define diversas classes de erro diferentes, que são disparados pelo interpretador em tempos de execução, estas constantes servem como um BITMASK e podem ser usadas para determinar para uma ou para outra rotina queis erros serão tratados e por onde.

error_reporting(int $nível = ?): int – Define quais os tipos de erro serão reportados pelo PHP, note que essa diretriz, vai determinar de acordo com a constante numérica quais os erros que serão reportados, abaixo a lista das constantes, e qual o tipo de erro que é reportado conforme seu tipo ou grupo. O PHP tem vários níveis de erros, usando esta função você pode definir o nível durante a execução do seu script. O $nivel é uma constante em nível de BITMASK, ou seja, determina um bit em uma sequencia, usar constantes é fortemente encorajado para assegurar compatibilidade com versões futuras, pois novos níveis de erros podem ser adicionados e o intervalo dos inteiros aumenta, assim antigos níveis de erro baseados em inteiros podem não funcionar como esperado.  Note que você pode desligar os alertas de erros, e esse é um nível quase nunca recomendado, mesmo em ambientes de produção, pois desse modo nem erros fatais serão registrados, para ambientes de produção, o indicado é não exibir os erros na saída padrão (browser) e registra-los em logs específicos, e veremos adiantes como isso é feito.

error_reporting(0); – Desliga todos os erros
error_reporting(E_ERROR | E_WARNING | E_PARSE); – Registra os erros que causam falhas diretas e alertas de ocorrência, é o mais indicado para ambientes de produção.
error_reporting(E_ALL ^ E_NOTICE); – representa todos os erros, exceto noticias do PHP é o padrão da instalação, e o indicado para servidores de teste e homologação de aplicações.
error_reporting(E_ALL); – Reporta TUDO, é o mais indicado para ambientes de desenvolvimento, já que até mesmo informações de versões futuras e incompatibilidades serão reportadas.

Erros e Logs
Valor Constante Descrição Nota
1 E_ERROR (integer) Erros fatais em tempo de execução. Estes indicam erros que não podem ser recuperados, como problemas de alocação de memória. A execução do script é interrompida.
2 E_WARNING (integer) Avisos em tempo de execução (erros não fatais). A execução do script não é interrompida.
4 E_PARSE (integer) Erro em tempo de compilação. Erros gerados pelo interpretador.
8 E_NOTICE (integer) Notícia em tempo de execução. Indica que o script encontrou alguma coisa que pode indicar um erro, mas que também possa acontecer durante a execução normal do script.
16 E_CORE_ERROR (integer) Erro fatal que acontece durante a inicialização do PHP. Este é parecido com E_ERROR, exceto que é gerado pelo núcleo do PHP. desde o PHP 4
32 E_CORE_WARNING (integer) Avisos (erros não fatais) que aconteçam durante a inicialização do PHP. Este é parecido com E_WARNING, exceto que é gerado pelo núcleo do PHP. desde o PHP 4
64 E_COMPILE_ERROR (integer) Erro fatal em tempo de compilação. Este é parecido com E_ERROR, exceto que é gerado pelo Zend Scripting Engine. desde o PHP 4
128 E_COMPILE_WARNING (integer) Aviso em tempo de compilação. Este é parecido com E_WARNING, exceto que é geredo pelo Zend Scripting Engine. desde o PHP 4
256 E_USER_ERROR (integer) Erro gerado pelo usuário. Este é parecido com E_ERROR, exceto que é gerado pelo código PHP usando a função trigger_error(). desde o PHP 4
512 E_USER_WARNING (integer) Aviso gerado pelo usuário. Este é parecido com E_WARNING, exceto que é gerado pelo código PHP usando a função trigger_error(). desde o PHP 4
1024 E_USER_NOTICE (integer) Notícia gerada pelo usuário. Este é parecido com E_NOTICE, exceto que é gerado pelo código PHP usando a função trigger_error(). desde o PHP 4
2048 E_STRICT (integer) Notícias em tempo de execução. Permite ao PHP sugerir mudanças ao seu código as quais irão assegurar melhor interoperabilidade e compatibilidade futura do seu código. desde o PHP 5
4096 E_RECOVERABLE_ERROR (integer) Erro fatal capturável. Indica que um erro provavelmente perigoso aconteceu, mas não deixou o Engine em um estado instável. Se o erro não for pego por uma manipulador definido pelo usuário (veja também set_error_handler()), a aplicação é abortada como se fosse um E_ERROR. desde o PHP 5.2.0
8192 E_DEPRECATED (integer) Avisos em tempo de execução. Habilite-o para receber avisos sobre código que não funcionará em futuras versões. desde o PHP 5.3.0
16384 E_USER_DEPRECATED (integer) Mensagem de aviso gerado pelo usuário. Este é como um E_DEPRECATED, exceto que é gerado em código PHP usando a função trigger_error(). desde o PHP 5.3.0
30719 E_ALL (integer) Todos erros e avisos, como suportado, exceto de nível E_STRICT no PHP < 6. 32767 no PHP 6, 30719 no PHP 5.3.x, 6143 no PHP 5.2.x, 2047 anteriormente

Os valores acima (numéricos ou simbólicos(constantes) são usados para criar um bitmask que especifica quais erros reportar.Você pode usar os operadores de Bit-a-Bit para combinar estes valores ou mascarar certos tipos de erro. Note que somente ‘|’, ‘~’, ‘!’, ‘^’ and ‘&’ serão ententidos dentro do php.ini o uso do registrador de erros, pode ser combinado com outras diretrizes 

display_errors – Determina se os erros devem ser impressos na tela como parte da saída ou se devem ser ocultados do usuário. O valor “stderr” envia os erros para stderr (log do sistema) em vez de stdout (browser). note, que apresentar erros no STDOUT  é um recurso para dar suporte ao seu desenvolvimento e nunca deve ser usado em sistemas de produção. Mesmo que essa diretriz possa ser configurado em tempo de execução (com ini_set()), ele não terá nenhum efeito se o script tiver erros fatais. Isso ocorre porque a ação em tempo de execução desejada não é executada.

display_startup_errors – Mesmo quando display_errors está ativado, erros que ocorrem durante a sequência de inicialização do PHP não são exibidos. É altamente recomendável manter display_startup_errors desativado, exceto para depuração e ambientes de desenvolvimento.

log_errors – Informa se as mensagens de erro de script devem ser registradas no log de erros do servidor ou no error_log. Essa opção é, portanto, específica do servidor. É altamente recomendável usar o registro de erros em vez de exibir erros em sites de produção. Essa diretriz combinada com error_reporting, vai determinar onde e como os erros serão registrados.

log_errors_max_len – Define o comprimento máximo de log_errors em bytes. Em error_log, informações sobre a fonte são adicionadas. O padrão é 1024 e 0 não aplica um comprimento máximo. Esse tamanho é aplicado a erros registrados, erros exibidos e também a $php_errormsg, mas não à funções chamadas explicitamente como error_log(). Quando um valor é utilizado, o valor é medido em bytes. A notação resumida do php pode também ser usada.

ignore_repeated_errors – Não registrar mensagens repetidas. Erros repetidos devem ocorrer no mesmo arquivo e na mesma linha, a menos que ignore_repeated_source seja definido como verdadeiro.

ignore_repeated_source – Ignora a fonte da mensagem quando estiver ignorando mensagens repetidas. Quando esta configuração estiver On, você não registrará erros com mensagens repetidas de arquivos ou linhas diferentes.

Se você estiver usando uma instalação de desenvolvimento em PHP, execute a partir da linha de comando via php -S localhost:8080 >> ERROR.LOGS, cada erro / aviso / aviso será relatado na própria linha de comando, e direcionado para o arquivo ERROR.LOGS com o nome do arquivo, número da linha e pilha de execução. Portanto, se você deseja manter um registro de todos os erros, mesmo após o recarregamento da página (para obter ajuda na depuração, talvez), executar o servidor de desenvolvimento PHP pode ser útil e recomendado nessas situações.

Manuseando os LOGS DO S.O. – Logs próprios do Sistema

Registrar logs é uma obrigação para os desenvolvedores de hoje, principalmente em sistemas que rodam com uma interface de rede, e que podem acessar outros serviços disponibilizados não só no no hospedeiro atual, como em outros sistemas distribuidos, por este motivo é um ponto muito importante entender os logs do Sistema, como visualizá-los e quais logs são mais importantes para o seu trabalho.  Os logs do Linux e de outros sistemas baseados em UNIX e POSIX fornecem uma linha de tempo dos eventos que abrengem desde o kernel, aplicativos e sistemas e são uma valiosa ferramenta de solução de problemas, portanto quando você encontra problemasé essencial, gravar dados nesses registros e fazer a análise de arquivos de log é a primeira coisa que um administrador precisa fazer quando um problema é descoberto.

Sistemas baseados em Windows não possuem um sistema nativo e centralizador de LOGs porém as versões mais novas (em especial a partir do 8.1) a microsoft vem implementando sistemas de log muito similares aos usados no UNIX, e no caso específico do PHP a versão compilada oficial distribuida em windows.php.net possui rotinas próprias que usam e implementam um sistea de LOG similar para manter a compatibilidade com os sistemas baseados em POSIX.

Basicamente, o PHP implementa 3 funções que tem a finalidade de registrar os LOGs usando o daemon do SO, são elas:

openlog(string $prefix, int $flags, int $facility): bool – Abre uma conexão com o log do sistema (que em POSIX pode ser registrado na máquina local, ou mesmo em máquinas remotas, especificas para registros de LOGs) seu uso é opcional, e caso ela não tenha sido chamada, a própria função syslog() vai fazer uma chamada usando os dados básicos e registrando dentro do log do próprio PHP. É uma boa prática geral logs diferentes conforme o tipo/necessidade da aplicação, e também, você pode usar regsitros específicos para a sua aplicação, vamos explicar isso abaixo. O parâmetro $prefix é um prefixo de texto enviado no inicio da mensagem. O argumento $flags é usado para indicar quais opções de log serão usadas ao gerar uma mensagem de log, e podem ser os seguinte:

Constante Descrição
LOG_CONS se houver um erro ao enviar dados para o registrador do sistema, grave diretamente no console do sistema
LOG_NDELAY abra a conexão com o logger imediatamente
LOG_ODELAY (padrão) atrasar a abertura da conexão até que a primeira mensagem seja registrada
LOG_PERROR imprimir mensagem de registro também para erro padrão
LOG_PID incluir PID em cada mensagem

Você pode usar uma ou mais dessas opções. Ao usar várias opções que você precisa pode combinar usando os operadores de BIT OR (|) ou seja, para abrir a conexão imediatamente, escreva para o console e inclua o PID em cada mensagem, você usará:LOG_CONS | LOG_NDELAY | LOG_PID.

Já o argumento $facility é usado para especificar que tipo de programa está registrando a mensagem, isso permite que você especifique (na configuração do syslog de sua máquina) como as mensagens provenientes de diferentes instalações serão tratadas, e seus valores podem ser:

Constante Descrição
LOG_AUTH mensagens de segurança / autorização (use LOG_AUTHPRIVem vez disso em sistemas onde essa constante é definida)
LOG_AUTHPRIV mensagens de segurança / autorização (privadas)
LOG_CRON daemon do relógio (cron e at)
LOG_DAEMON outros daemons do sistema
LOG_KERN mensagens do kernel
LOG_LOCAL0 … LOG_LOCAL7 reservados para uso local, não estão disponíveis no Windows
LOG_LPR subsistema de impressora de linha
LOG_MAIL subsistema de correio
LOG_NEWS Subsistema de notícias USENET
LOG_SYSLOG mensagens geradas internamente pelo syslogd
LOG_USER mensagens genéricas no nível do usuário
LOG_UUCP Subsistema UUCP

O único argumento válido nos sistemas WINDOWS é LOG_USER, os demais são ignorados pelo próprio PHP. E a função retorna SUCESSO (true) caso o syslog tenha sido criado ou FALSE caso tenha falhado.

closelog(): bool – Esta função Fecha a conexão com o registrador do sistema. Novamente seu uso é opcional, e se não existirem logs abertos, o PHP define o padrão para escrever os registros. Esta função retorna TRUE caso tenha fechado o Syslog aberto atualmente, e FALSE caso não exista Syslog aberto, ou ele não consiga ter sido fechado.

syslog(int $priority, string $message): bool – É a função que faz o anvio da mensagem para o LOG do sistema propriamente dita. Você deve ter configurado o sistema de LOGs em algumas distribuições UNIX e LINUX porém, a maioria delas vem com o sistema previamente habilitado e pré-configurado, não é escopo deste curso os detalhes de configuração do SO, e você pode utilizar o próprio comando MAN para pesquisar opções de configuração, ou dezenas de conteúdos voltados a SysAdmins que ensinam a configurar especificamente o syslog em diversas distribuições linux e outras baseadas em POSIX. O argumento $priority é um ou mais dos recursos definidos, como segue:

Constante Descrição
LOG_EMERG sistema está inutilizável, e inoperante
LOG_ALERT ação deve ser tomada imediatamente, pois pode causar uma instabilidade futura e interrupções do sistema
LOG_CRIT condições críticas, que precisam de atenção, mais que não causaram problema atual, porém devem ser verificadas
LOG_ERR condições de erro, não causaram a interrupção do sistema, porém causaram problemas naquele momento
LOG_WARNING condições de alerta, não causou problema e não gerou transtornos ao usuário ou sistema, porém, podem gerar problemas em breve, se não for tomadas providências por parte dos programadores e administradores
LOG_NOTICE condição normal, mas significativa, ou seja, algo anormal que pode ter sido usado, ou simplesmente uma notificação para o administrador, como uso de um recurso
LOG_INFO mensagem informativa, é o nível padrão de registros do sistemas, por exemplo usado para log de acesso ou de recursos
LOG_DEBUG mensagem de nível de depuração, usada para interceptar por exemplo mensagens de erro do usuário ou do core do PHP para que os administradores e programadores possam fazer a depuração do sistema a procura de erros sem exibir no entanto mensagens específicas para os usuários

Já $message é o texto puro da mensagem a ser escrita no arquivo de LOG. Esta mensagem deve ser uma string, sem caracteres de controle e quebras de linha por exemplo, pois alguns sistemas podem ter problemas cm o tratamento desse tipo de mensagens. Nos sistemas Windows, o SysLog usa o serviço de LOG DE EVENTOS para simular o sistema UNIX/POSIX e manter uma certa compatibilidade.

NOTAS TÉCNICAS: o PHP define a diretriz syslog.filter que pode ser configurada pelo ini_set() ou diretamente no php.ini e especifica o tipo de filtro usado para filtrar as mensagens registradas. Caracteres permitidos são passados sem modificações, todos os outros são escritos em sua representação hexadecimal prefixado com \x. Existem três tipos de filtros suportados: all – todos os caracteres, no-ctrl – todos os caracteres, exceto os caracteres de controle, ascii – todos os caracteres ASCII imprimíveis e NL. Estas configurações somente são efetivas se error_log estiver definido como “syslog”. syslog.ident é uma outra identificação, e especifica a string ident que é anexada a todas as mensagens.

É uma boa prática SEMPRE usar openlog e closelog para que suas mensagens sejam sempre direcionadas para a saída correta, pois caso contrário, suas mensagens podem estar em diferentes arquivos, como o arquivo de log do apache, ou do próprio php, ou mesmo logs genéricos do sistema operacional. Você também pode direcionar mensagens para multiplas saídas simultaneamente, basta você usar uma série de comandos como em:

syslog(LOG_INFO|LOG_LOCAL0, "message for local0");
syslog(LOG_INFO|LOG_LOCAL1, "message for local1");

Um outro detalhe importante, é que o uso de LOG em sistemas POSIX não causa atrasos ou problemas de lentidão pois o próprio SO possui rotinas para salvar as mensagens em buffer, e também em sistemas que permitem uso de journaling, eles são escritos lá, e somente em momentos posteriores operações de I/O em disco intensas são geradas.

Outras Funções Para Tratamento e Exibição de Erros e Excessões

debug_backtrace(int $options = DEBUG_BACKTRACE_PROVIDE_OBJECT, int $limit = 0): array – Gera uma PILHA DE EXECUÇÃO, em computação, um rastreamento de pilha é um relatório dos quadros de pilha ativos em um determinado ponto no tempo durante a execução de um programa. Quando um programa é executado, a memória geralmente é alocada dinamicamente em dois lugares; a pilha e o heap. Os dois parâmetros são $options que pode receber 2 valores definidos nas constantes DEBUG_BACKTRACE_PROVIDE_OBJECT que diz se deve ou não preencher o índice do “objeto” e DEBUG_BACKTRACE_IGNORE_ARGS se deve ou não omitir o índice “args” e, portanto, todos os argumentos de função / método, para economizar memória. $limit determina a quantidade de registros que será exibida, por padrão, o PHP define limit=0 e apresenta TODOS. O Array retornado, contém 1 ou mais entradas, onde cada entrada representa um item da pilha, e cada entrada é definida por um array associativo que pode uma ou mais entradas onde:

Nome Tipo Descrição
function string O nome da função atual. Veja também __FUNCTION__
line int O número da linha atual. Veja também __LINE__
file string O nome do arquivo atual. Veja também __FILE__
class string O nome da classe atual . Veja também __CLASS__
object object O objeto atual
type string O tipo de chamada atual. Se uma chamada de método, “->” é retornado. Se uma chamada de método estático, “::” é retornado. Se uma função for chamada, nada será retornado.
args array Se estiver dentro de uma função, lista os argumentos da função. Se estiver dentro de um arquivo incluído, lista os nomes dos arquivos incluídos.

Esta função é muito útil, principalmente durante a fase de HOMOLOGAÇÃO do sistema, onde já temos usuários reais utilizando, porém, ainda queremos ter acesso a pilhas de execução, para avaliar em casos de erros quais as possíveis causas e onde eles estão ocorrendo, um dump neste array de resposta da função para um arquivo de LOG pode ser de grande valor para avaliar todas as chamadas internas e a pilha de execução do sistema.

debug_print_backtrace(): void – A imprime um backtrace de PHP. Ele imprime as chamadas de função, arquivos incluídos / necessários (requeridos) e utiliza a saída padrão, ou seja, se você estiver gerando um arquivo em outro formato, ou usando a função, saídas com esses dados podem ser geradas no browser, portanto lembre-se de capturar as saídas com as funções corretas de fluxo de saída como ob_start(), ob_get_contents entre outras. Lembre-se essas funções serão vistas mais a frente em nosso curso, então não se preocupe com elas agora.

trigger_error(string $error_msg, int $error_type = E_USER_NOTICE): bool – É tambem apelidada como user_error() e ambas tem exatamente as mesmas características, sendo mantidas somente para retrocompatibilidade. Prefira usar o nome novo trigger_error. Esta função gera uma mensagem para o tratamento de erro em nível de usuários, o argumento $error_msg é a mensagem de texto que será disparada para o controle de erro atual, que pode ser exibir no browser, ou salvar em disco ou mesmo gerar um email ou um log no sistema, essa configuração é definida no PHP.INI e já foi estudada anteriormente, já $error_type é um valor definido pelas constantes e pode ser definida como E_USER_NOTICE, E_USER_ERROR e E_USER_WARNING e dispara um nível diferente de mensagem, que pode ser tratado de maneira diferente conforme as suas configurações de tratamento de erro. É muito usada com a função set_error_handler() para definir exatamente como lidar com mensagens e erros do lado do usuário.

A mensagem deve ser usada em conjunto com htmlentities caso possa conter conteúdo HTML e precise ser exibida para o usuário em um browser por exemplo. E também está limitada a 1024 (1Kb) caracteres, qualquer coisa acima disso será truncada. A ideia é nunca fornecer nomes de arquivo, números de linha e códigos criptográficos ou senhas ao usuário. Use a trigger_error() depois de usar set_error_handler() para registrar a sua própria função de retorno de chamada e tratamento de error que registra ou envia por e-mail os códigos de erro para você, e exibe uma mensagem simples e amigável para o usuário. E ative uma função de tratamento de erros mais detalhada quando precisar depurar seus scripts, ou estiver em ambientes de depuração e desenvolvimento. Algo similar ao código:

if (_DEBUG_) {
    set_error_handler ('debug_error_handler');
} else {
    set_error_handler ('nice_error_handler');
}

Por exemplo, se você está desenvolvendo um sistema que gera a saída em uma imagem, você deve poder gerar a imagem com um texto contendo o erro, ou simplesmente gerar uma imagem padrão, o mesmo ocorre por exemplo em saídas de uma API, onde você pode retornar um JSON com as mensagens do manipulador de erros, ou qualquer outra saída específica, sem se preocupar em quebrar a saída do seu script.

error_log( string $mensagem, int $mensagem_type = ?, string $destination = ?, string $extra_headers = ? ): bool – Envia uma mensagem de erro para as rotinas definidas para gerenciamento de erros ou para o manipulador padrão caso nenhum tenha sido definido. Onde $message é uma mensagem em forma de texto para as rotinas definidas para gerenciamento de erros. $message_type pode ser um definida em 4 formas, 0 = mensagem é enviada para o sistema de log, como definido na função error_log ou pela diretriz error_log no php.ini – 1 = a mensagem é enviada por mail() para o endereço definido no próximo argumento, este deve ser um e-mail válido e acessível pelo sistema hospedeiro. 2 – Não se mantém ativo desde a versão 4 do PHP e não possui mais utilidade – 3 = a mensegem é salva no arquivo definido no próximo argumento, o arquivo deve existir e o PHP deve possuir direito de escrita nele. $destination pode ser o email ou um caminho para um arquivo, conforme o parâmetro anterior. Por fim para mensagens enviadas por email, $extra_headers será enviada como argumentos para a função mail() interna do PHP e pode definir cabeçalhos para manipulação e assuntos diferenciados.

Lembre-se a função error_log pode escrever grandes quantidades de texto em arquivos do sistema o que pode acabar simplesmente travando o servidor por falta de espaço em disco, e gerando atrasos nas respostas, diferente das mensagens em syslog para salvar arquivos os arquivos e emails gerados, o PHP faz uso intenso de operações de I/O em disco e remotas (se assim estiver configurado) o que pode acarretar em perdas de performance e uso estensivo de espaço em disco, já que o mecanismo do PHP não possui operações de ciclagem automática de LOG e compactação de arquivos para reduzir o consumo de espaço. Portanto, é uma melhor prática analisar e eliminar seus LOGs periodicamente, ou criar rotinas no proprio sistema operacional, que faça a ciclagem (mantenha em leitura/escrita somente arquivos atuais, ou menores que um determinado tamanho, ou qualquer outra politica definida pelos Administradores.

Um outro detalhe, você pode usar um caminho relativo (relative path) porém, caso sua função de registro e tratamento de erros esteja sendo chamada de locais diferentes, pode ocorrer de você ter arquivos de log gerados em lugares diferentes, portanto, prefira uma diretiva global onde é possivel obter o diretório absoluto e usar sempre caminhos absolutos. Alguns SOs não permitem arquivos de tamanho maior do que 2Gb, e se o seu arquivo de log sofrer essa limitação, isso pode simplesmente deixar o PHP inoperante (erro 500) se ele não consegue usar o arquivo, ou simplesmente mensagens serem ignoradas se você não possui permissão de uso do arquivo.

ALERTA IMPORTANTE ! Como o e-mail usando-se o padrão do sendmail e do php não é criptografado, enviar dados sobre seus erros por e-mail usando a função error_log() pode ser considerado um risco de segurança, e o grau de risco depende de quanto e que tipo de informação você está enviando, mas o mero ato de enviar um e-mail quando algo acontece mesmo que não possa ser lido pois foi usada criptografia, ainda pode significar para um hacker que esteja monitorando o trafego do seu site, pode sinalizar que naquele ponto ele conseguiu gerar um erro, a segurança através da obscuridade é o tipo mais fraco de segurança, e é algo que você deve manter em mente, quando usar este tipo de técnica de rastreio de erros. E, claro, o que quer que você faça, certifique-se de que esses e-mails não contenham dados confidenciais do usuário.

error_get_last(): array – Retorna um array, que contem o ULTIMO ERRO OCORRIDO, o array com chaves “type”, “message”, “file” e “line”. Retorna null se não tiver ocorrido um erro até a chamada da função. Vela, o código abaixo, gera a seguinte saída:

<?php
echo $a;
print_r(error_get_last());
?>

A Saída

Array ( [type] => 8 [message] => Undefined variable: a [file] => C:\WWW\index.php [line] => 2 )

Onde, type é um dos valores das constantes já mostradas acima, e 8 significa: E_NOTICE, e message é a mensagem padrão gerada no sistema. Note que a variável $php_errormsg contém o texto da message e esta variável somente estará disponível dentro do escopo no qual o erro ocorreu, e somente se a opção de configuração track_errors estiver on. Esse retorno é o que o próprio PHP usa para relatar erros quando display_errors está como ligada, ou direcionada ao browser.

error_clear_last(): void – Limpa o registro de erros, tornando impossível obter o erro com uso de error_get_last(). Permite que você verifique se erros ocorreram até um momento, limpe o registro e inicie nova tratativa. Como em loopings ou outras situações onde erros não fatais possam estar sendo registrados.

Um detalhe, antigamente, no PHP4 e PHP5 era comum usar essas duas funções em conjunto, para fazer o manuseamento de cache de páginas, armazenando os conteúdos gerados de maneira estática, e dando a saida ou re-gerando de acordo com o estado armazenado dessas variáveis, porém, atualmente temos maneira muito mais eficientes de gerar e fazer o manuseio de cache, em diversas ferramentas, que abordaremos mais a frente.

set_error_handler(callback $error_handler, int $error_types = ?) – Esta função direciona para a função definida em callback com o nome $error_handler para u manipulador de erros comum, e $error_types são as constantes de erro ou conjunto delas que serão direcionadas para aquela função, note, você pode ter funções diferentes para manipular tipos diferentes de erro, e consequentemente gerar erros e tratamentos diferentes para o seu usuário. Esta função pode ser usada para definir a sua própria maneira de manipular erros em tempo de execução, por exemplo, em aplicações nas quais você precisa fazer fazer uma limpeza de dados/arquivos (um rollback em um banco de dados, depois que um erro ocorra, por exemplo) ou quando um erro crítico acontece, ou quando você precisa que haja um erro sob certa circunstancia. Lembre-se que quando uma funçõ tiver sido definida por set_error_handle(), o manipulador padrão do php é ignorado e somente a função vai receber o controle do script, e as configurações de error_reporting não serão respeitadas, pois sua função recebe o controle para todos os tipos definidos em $error_types, porém, você pode chamar error_reporting() sem argumentos para saber o valor atual e tomar as medidas cabíveis e apropriadas para cada nível. Um detalhe importante, o valor retornado do errorlevel para a sua função será 0 se um @ tiver sendo usado para suprir alertas em determinados blocos ou chamadas, no PHP 8 o valor para erros supridos pelo @ é 4437

A função chamada, pode retornar um valor (true) e a execução do script retorna para o ponto onde estava, ou seja, a próxima linha, ou então finalizar o script através da chamada de die(), é responsabilidade do desenvolvedor tomar as medidas corretas, caso a execução da função chegue ao fim, o controle é retornado para a próxima linha e o retorno true é adicionado. Os seguintes tipos de erros não podem ser manipulados com uma função definida pelo usuário através de set_error_handler E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING, e a maioria de E_STRICT  pois são erros que irão causar a finalização do PHP antes das instruções serem iniciadas, ou seja, são erros que não ocorrem durante a execução, e sim, durante uma inclusão de arquivo ou ou leituras externas que possam causar falhas no próprio interpretador. Se um erro acontecer antes que o script seja executado (exemplo em uploads de arquivos) a função personalizada de manipulação não pode ser chamada já que não estará registrada para isso neste momento.

A função do usuário precisa aceitar dois parâmetros: o código de erro, e uma string descrevendo o erro. Então tem três parâmetros opcionais que podem ser dados: o nome do arquivo no qual o erro aconteceu, o número da linha na qual o erro aconteceu, e o contexto no qual o erro aconteceu (uma matriz que aponta para a tabela de símbolos ativos no ponto em que o erro aconteceu). Uma função típica de tratamento de erros deve ser capaz de receber esses argumentos, ou um erro fatal pode ocorrer. O escopo de uma função de callback deve se parecer com:

handler(
    int $errno,
    string $errstr,
    string $errfile = ?,
    int $errline = ?,
    array $errcontext = ?
) {
switch ($errno) {
    case E_USER_ERROR:
        echo "<b>ERRO:</b> [$errno] $errstr<br />\n";
        echo "  Erro fatal na linha $errline em $errfile arquivo";
        echo ", PHP " . PHP_VERSION . " (" . PHP_OS . ")<br />\n";
        echo "Execução abortada...<br />\n";
        exit(1);
        break;
    case E_USER_WARNING:
        echo "<b>ALERTA</b> [$errno] $errstr<br />\n";
        break;

    case E_USER_NOTICE:
        echo "<b>AVISO</b> [$errno] $errstr<br />\n";
        break;

    default:
        echo "FALHA: [$errno] $errstr<br />\n";
        break;
    }
    return true;
}

Note, no exemplo de um manipulador, personalizado, você pode determinar se a saída do erro ocorre em tela (browser), em um arquivo de LOG, ou caso seu script esteja por exemplo criando uma imagem ou um gráfico, apresentar o erro dentro dessa imagem, enfim, você passa a ter o total controle, pode até mesmo executar um rollback em um banco de dados caso uma conexão esteja ativa, ou, com um pouco de tratamento, pode por exemplo usar variáveis de sessão ou tokens que determinem saidas de erro diferentes, como um JSON ou um XML ou qualquer outro formato que o PHP possa manipular, ou salvar um registro de LOG DE ERROS em um arquivo específico, (de preferência fora da área onde o servidor web tenha acesso) e mostrar uma mensagem elegante para o usuário, como com uso de um html e o que mais sua imaginação permitir. Observação útil – se o seu manipulador de erros gerar um erro, o PHP é inteligente o suficiente para usar o manipulador de erros interno para lidar com isso, evitando um looping infinito.

restore_error_handler() – Restaura a manipulação de erro para o manipulador padrão do PHP. Caso você tenha definido mais de um manipulador de erro, ele restaura para o anterior, e não para o padrão, você pode reverter diversas vezes até chegar ao manipulador anterior. Caso essa função seja chamada de dentro da função de manipulação de erro atual, o comportamento do PHP é inesperado, já que ele perde as referências de função, quando o manipulador esta ativo, esse comportamento pode gerar a perda de dados ou corrupção do serviço do PHP em algumas versões.

set_exception_handler(callback $exception_handler) – De mesmo modo que a set_error_handler, a função set_exception_handler define uma função de usuário para tratamento de exceções, se uma exceção não for pega em um bloco try/catch ela é transferida para a função definida. A Execução não parará depois que exception_handler é chamada, e a função já precisa estar definida para ser usada (criada anteriormente). Essa função de tratamento precisa aceitar um parâmetro, que será o objeto da exceção que foi disparado. O retorno da função é o tratador de excessão anteriormente definido ou null caso seja o manipulador de exceções padrão do PHP.

Coisas que você deve estar ciente: Um manipulador de exceções trata as exceções que não foram detectadas antes, é da natureza de uma exceção que ele interrompa a execução de seu programa, e uma vez que o php declara uma situação excepcional na qual o programa não pode continuar e como essa função só é atingida, se o seu programa padrão não tratou antes, seu código sinaliza que ele não está ciente da situação e não pode continuar, isso implica que, retornar ao script é simplesmente impossível quando o tratador de exceção já foi chamado, uma vez que uma exceção não capturada não é um aviso, use seu próprio sistema de log de depuração ou notificação para coisas como essa, e saiba que neste ponto, você tem que terminar seu script, portanto, feche conexões ativas, se aplicável, use o rollback para o banco de dados, entre outros procedimentos.

Embora ainda seja possível chamar funções a partir do seu script, de dentro do manipulador de exceções, uma vez que o manipulador de exceções já foi chamado, não tem possibilidade de retornar a execução do script, ao terminar sua função, o PHP irá morrer sem deixar nenhuma informação, ou dependendo registrar no LOG uma “exceção não capturada com quadro de pilha desconhecido”. Portanto, se você chamar funções a partir de seu script neste ponto, certifique-se de capturar todas as exceções que possam ocorrer por meio de try..catch dentro do manipulador de exceções, ou o PHP pode se tornar instável.

Para que vocês não interpretem mal o significado essencial do manipulador de exceções: ele só pode ser usado para lidar com o aborto de seu script com elegância, por exemplo, gerando um erro amigavel ao usuário, renderizando uma página de erro agradável em uma imagem ou no formato correto como um JSON ou XML ou PDF etc, escondendo informações que não devem vazar para o público, você pode querer escrever em seu log ou enviar um e-mail para o administrador do sistema ou coisas assim. Em outras palavras: Redirecionar todos os erros de php de um manipulador de erros usando exceções, incluindo avisos, não é uma ideia boa, a não ser que você esteja em um ambiente de testes ou de desenvolvimento e pretende ter seu script abortado toda vez que você não definir uma variável ou usar uma função que está sinalizada como depreciada (deprecated).

restore_exception_handler() — Restaura a função tratadora de exceções anterior, ou de volta ao padrão do PHP, essa função funciona de maneira analoga a restore_error_handler() e seu retorno é true sempre.

Com isso chegamos ao fim dessa aula, e você aprendeu como manipular e trabalhar com um sistema simplificado de cache, além de aprender a usar de maneira correta e segura os manipuladores de erros e de exceções. Na proxima aula, vamos aprender sobre uma outra extensão do PHP que implementa a importação de funções estrangeiras (FFI – Foreign Function Interface) e como utilizar um poderoso sistema de cache chamado OPCache, além de conhecer os manipuladores de fluxo de saída e de buffer de saída, que são importantes extensões do PHP para trabalho com cache e armazenamentos de dados pré processados, que podem ter sido gerados com o proprio PHP ou com outras linguagens de programação. Até lá.

Deixe um Comentário