Um programa é um texto destinado a expressar a computação de um resultado que responde a uma pergunta sobre os dados. Por exemplo, um programa de classificação pega uma lista de valores (os dados) e deve calcular um resultado que é outra lista dos mesmos valores, mas classificados de acordo com alguma função de comparação.
Este texto deve ser expresso formalmente em algum tipo de linguagem que é (ou deveria ser) definida com precisão, tanto em relação ao que constitui um texto legítimo de programa quanto em como algum significado computacional pode ser associado a esse texto. Essa definição precisa é geralmente abstrata (possivelmente matemática) e pode ignorar alguns problemas concretos, como limitações do computador.
Mas então, a linguagem é implementada para que os programas possam ser executados. Existem várias maneiras de executar essa implementação, usando um intérprete do texto original do programa ou compilando para algum código intermediário (código de bytes, por exemplo), e possivelmente interpretando esse código intemediato ou compilando-o ainda mais no código da máquina. E pode haver outras variações. E, é claro, existem muitas maneiras de escrever um compilador ou um intérprete e muitas máquinas para executá-los.
Além disso, pode haver várias definições formais e várias implementações, esperançosamente consistentes.
Os erros podem ser classificados em relação à estrutura de uma ou de uma definição formal ou de uma implementação. No entanto, você pode ter situações estranhas em que os erros são classificados de acordo com uma implementação de referência antiga que não é mais a que está sendo usada.
Isso significa essencialmente que a classificação dos erros não é realmente um tópico muito estável . Além disso, algumas linguagens podem distinguir vários níveis de erros, dependendo se algo está definitivamente errado (o programa nem será executado) ou se você está fazendo algo não recomendado, mas isso ainda produzirá algum cálculo, que pode fazer sentido. Isso até se reflete em recursos de linguagens de programação, como exceções, que podem ou não ser recuperadas.
Distinções padrão são:
Erros de sintaxe : o texto fornecido não está em conformidade com a estrutura de um texto de programa, independentemente do que ele deva significar. Isso pode se referir apenas a uma sintaxe formal de linguagem, geralmente sem contexto. Às vezes, pode ir além e incluir a verificação de alguns recursos básicos, como declarações de variáveis (se houver) ou consistência de tipo, embora esses também possam ser considerados como erros semânticos.
Erros semânticos ou lógicos : são erros que podem ser detectados ao executar o programa, devido ao fato de o programa executar um cálculo que não faz sentido semântico, como dividir por zero ou indexar uma matriz fora do intervalo. limites. Chamar uma função com o número errado de argumentos ou com argumentos do tipo errado também pode ser considerado um erro semântico. Em alguns idiomas, os erros podem realmente ser definidos pelo usuário por meio de exceções, quando correspondem a alguma semântica de nível superior definida pelo usuário para parte de seu programa (embora haja outros usos de exceções). Alguns desses erros também são chamados de erros em tempo de execução, pois são detectados em tempo de execução, mas não devem ser confundidos com erros de limitação de hardware.
Erros de limitação de hardware : são erros devido ao fato de a implementação estar em uma máquina real que possui limitações. Por exemplo, pode ser um número inteiro grande demais para caber em uma palavra de memória ou falta de memória suficiente para criar uma estrutura de dados. Eles também geralmente são detectados em tempo de execução.
Em relação aos erros semânticos e erros de limitação de hardware, às vezes é possível detectá-los antes de executar o programa, com o que é chamado de análise semântica estática. Esse é geralmente o caso de declarações ou variáveis não inicializadas, erros de tipo ou divisão por zero e alguma verificação vinculada à matriz, mas isso pode ir muito além. A análise semântica estática também é importante nos compiladores para muitas técnicas de otimização. Geralmente, existe uma separação entre semântica estática e dinâmica. A melhor definição que posso imaginar é que a semântica estática diz respeito a propriedades que são decidíveis em tempo de compilação, sem os dados reais. Portanto, a divisão por zero não faria parte da semântica estática em geral. Isso significa que alguns erros semânticos dinâmicos ainda podem ser detectados às vezes em tempo de compilação. O mesmo vale para erros de limitação de hardware.
Porém, todo designer ou implementador de linguagem tem o direito de classificar os erros como deseja , a menos que esteja vinculado a um contrato ou licença. Esse pode ser o caso do seu exemplo PHP. E qualquer um pode também fazer uma distinção entre erros semânticos e lógicos, embora eu não saiba como definir uma diferença, a menos que seja informado em detalhes sobre esses erros. Um poderia ser usado para indicar erro de intenção (erro lógico) e não seria detectável pelo sistema.
Observe que pode haver outros tipos de erro em um programa , que geralmente não serão detectados pelo sistema. Isso inclui, em particular, inconsistências do programa com sua especificação (ou o que chamei de erro de intenção: o usuário não está fazendo o que ele quis fazer), ou possivelmente erros na própria especificação. Também pode haver erros devido a limitações de hardware, como erros de arredondamento ao trabalhar com números reais.