O que é um construtor da linguagem? – php característica-linguagem

Pergunta:


Em PHP, já li e ouvi várias vezes a respeito dos Construtores da Linguagem. Os casos que sempre ouvi falar deles foi em casos onde se dizia: “prefira usar X ao invés de Y, pois Y é uma função e X é um construtor da linguagem”.

Um dos casos que já li algo a respeito seria no caso de usar isset pra checar um índice de um array, ao invés de array_keys_exists (sei bem a diferença entre os dois, mas não é o foco da pergunta). A recomendação é porque array_key_exists é uma função, e isset, um construtor.

Sendo assim, eu queria saber algumas coisa:

  • O que seria um construtor da linguagem em PHP? Quais são eles?

  • Por que a documentação do PHP recomenda, em alguns casos, usar construtores da linguagem ao invés das funções?

  • Nos casos em que os construtores da linguagem se assemelham às funções (como isset, empty e require), quais são as principais diferenças entre os Construtores da linguagem e as funções?

Um exemplo da pergunta 2: usar isset ao invés de is_null (que é uma função), onde isset também retorna True caso o valor da variável seja NULL.

Autor da pergunta Wallace Maxters

Maniero

O que seria um construtor da linguagem em PHP? Quais são eles?

Alguns não gostarão disto, mas eu tenho que dizer que costuma ser gambiarra, pelo menos a maioria dos casos em PHP.

Tudo que o compilador trata de forma especial podemos considerar como construção da linguagem (não gosto do termo construtor aí porque ele não é bem um agente e sim uma característica, então vou usar construção). Uma função de forma geral é uma construção da linguagem, porque ela trata de forma especial. Digo, a criação de função em si é uma construção. O if é uma construção. Mas usar uma função é algo do usuário, mesmo que seja uma função padrão da biblioteca já não pertence à linguagem, a função não tem significado especial.

Por que a documentação do PHP recomenda, em alguns casos, usar construtores da linguagem ao invés das funções?

Acredito que por ela ter mais eficiência, ou porque já está pronto, ou porque é a única opção mesmo (depende do caso). De fato uma construção pode ser mais eficiente porque o compilador/interpretador pode tratar de forma melhor do que uma função poderia, mas em certas linguagens isso não ocorre ou não é necessário, ou o ganho é irrisório. Curiosamente linguagens de script, como é o caso de PHP, não precisam muito de otimizações e uma função seria adequada. Construções de linguagem podem ser úteis quando o compilador pode garantir um código target melhor. E curiosamente essas linguagens tem capacidade de otimizar funções a tal ponto que torna a construção desnecessária. Então podemos falar em falha do compilador do PHP também.

Embora hoje eu acho que tem muito disto por legado. Hoje talvez fariam diferente. Ou não, afinal em toda versão desta linguagem colocam coisas ruins novas.

Nos casos em que os construtores da linguagem se assemelham às funções (como isset, empty e require), quais são as principais diferenças entre os Construtores da linguagem e as funções?

O require eu acho que deve ser construção mesmo porque ele muda o código fonte que está sendo trabalhando ali, tem uma influência maior na execução, mas em PHP muda menos. Note que ele pode ser usado até sem parênteses, assim como o echo e outros assim podem ser usados sem.

Quem sabe o fato de não obrigar os parenteses tenha sido o motivo para preferir ser construção da linguagem. Tem linguagem que permite deixá-los de lado em alguns casos de funções sem que precise ser construção de linguagem.

O empty() por exemplo provavelmente pode ter alguma otimização porque ela trata de vários tipos e aí teria um enorme switch para selecionar a ação de acordo com o argumento usado e isto teria um custo, mesmo que nem sempre expressivo porque a maioria dos tipos estaria no início da tabela e e as verificações não são, ou não deveriam ser feitas uma a uma, mas vai saber se o switch do PHP não é otimizado assim.

O isset() pode ser porque envolve coisas internas da linguagem, mas poderia ser sim uma função.

O que seria um construtor da linguagem em PHP? Quais são eles?

O construtor da linguagem ou palavas reservadas são as gramáticas definidas /usadas pelo analisador léxico para interpretar uma sintaxe. Programas como lex/flex e yacc/bison que compõe esse universo de analise léxica. Por exemplo: Se você quiser escrever uma nova linguagem você terá que definir quais os comandos ela aceita ou não, em qual ordem dever ser escrito e definir cada detalhe para que o computador saiba interpretar os comandos e inclusive saber o que fazer quando algo estiver escrito na sua nova linguagem.

Suponhamos que você tenha definido entre outros as palavras (“procurar” e “negativar”), essas palavras serão reservadas. o lex/flex em conjunto yacc/bison trabalham para ler essas entradas e gerar um código em C já otimizado para reconhecer a sua sintaxe e trata-la conforme você definiu. O commando “isset” do php também é definido na gramatica da linguagem, mais especificamente em no arquivo zend_language_scanner.l o código fonte está disponível se desejar ter mais informações. Já a função “array_key_exists” ela não está presente do construtor léxico. Ela não é uma palavra reservada por não fazer da sintaxe (idioma) php, porém ela existe e agrega funcionalidades ao core do php e compõe o módulo standard do php , “array_key_exists” você pode achar mais informações no “php_array.h” e “array.c“, como pode ser observado ao contrário do isset que é definda na construção da sintaxe, ela não é definida na criação da linguagem, mas sim “adicionada” “PHP_FUNCTION(array_key_exists)”, assim como você pode poderia estar criando um módulo próprio e adicionando qualquer outra função.

Você pode encontrar alguns token usados no php direto no manual ou ainda no código fonte. Se desejar, pode também encontrar no próprio stackoverflow um post sobre análise léxica também tem muito material interessante sobre isso na internet.

Observação:

lex, flex, yacc e bison são programas diferentes. E inseridos no contexto apenas para facilitar, caso deseje obter mais referências sobre o assunto

Por que a documentação do PHP recomenda, em alguns casos, usar construtores da linguagem ao invés das funções?

No caso do isset e array_key_exists a recomendação que encontrei no site é devido à questões de performance, conforme na própria página da documentação do php, uma das sugestões não é de substituir, mas de usar ambos. Existe um Benchmark, mostrando o tempo de execução do algoritmos.

O motivo de um ser mais rápida do que a outra, não é exclusivamente o fato de uma ser um construtor de linguagem e outra ser uma função, mas também a complexidade do algoritmos para executar um isset ou um array_key_exists.

A complexidade do algoritmo pode fazer com que você ganhe ou perca desempenho dependendo do volume do uso. Como cada caso é um caso, o ideal é ler tanto a documentação quanto a nota para obter mais informação, e caso ainda reste dúvida, tenha necessidade e/ou interesse é possível ter acesso ao código fonte.

No isset e array_key_exists o que foi apontado foi o desempenho, porém podem ser questões desde de depreciação, retro compatibilidade e etc…,mas volto a dizer, cada caso é um caso.

A título de curiosidade essa é a implementação do array_key_exists no
php 7.1

PHP_FUNCTION(array_key_exists)
{
    zval *key;                  /* key to check for */
    HashTable *array;           /* array to check in */

    ZEND_PARSE_PARAMETERS_START(2, 2)
        Z_PARAM_ZVAL(key)
        Z_PARAM_ARRAY_OR_OBJECT_HT(array)
    ZEND_PARSE_PARAMETERS_END();

    switch (Z_TYPE_P(key)) {
        case IS_STRING:
            if (zend_symtable_exists_ind(array, Z_STR_P(key))) {
                RETURN_TRUE;
            }
            RETURN_FALSE;
        case IS_LONG:
            if (zend_hash_index_exists(array, Z_LVAL_P(key))) {
                RETURN_TRUE;
            }
            RETURN_FALSE;
        case IS_NULL:
            if (zend_hash_exists_ind(array, ZSTR_EMPTY_ALLOC())) {
                RETURN_TRUE;
            }
            RETURN_FALSE;

        default:
            php_error_docref(NULL, E_WARNING, "The first argument should be either a string or an integer");
            RETURN_FALSE;
    }
}

Nos casos em que os construtores da linguagem se assemelham às funções (como isset, empty e require), quais são as principais diferenças entre os Construtores da linguagem e as funções?

Os “Construtores da linguagem” como citado anteriormente seriam a gramática da linguagem “consultar análisador léxico”. Já as funções “nesse caso” seriam outros recursos (funções) definidas em módulos e extensões do php.

Espero que isso te ajuda de alguma forma.

Fonte

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *