Photo by Henri L. on Unsplash

Nos bastidores do PHP

O manual do PHP diz que um array no PHP é um mapa ordenado que relaciona valores a chaves e é otimizado para vários usos diferentes: array, lista, hashtable (não só array mas basicamente tudo no PHP é uma hashtable – se quiser saber mais sobre o assunto acesse Understanding PHP’s internal array implementation), dicionário, coleção, pilha, fila e mais, possibilitando os valores do array serem outros arrays e arrays multidimensionais.

Graças ao hashtable escrito em C no código-fonte do PHP, os arrays são um diferencial em relação a outras linguagens de desenvolvimento web.

Você pode manipular um array PHP utilizando o foreach() para resolver qualquer tipo de controle de dados.

Por exemplo, Deus quer marcar o programador da sua equipe que mais toma café durante o dia, a partir de um array $devs:

$devs = [
    ['id' => 1, 'name' => 'Carvalho', 'age' => '23', 'coffee' => 71],
    ['id' => 2, 'name' => 'Zacarias', 'age' => '20', 'coffee' => 5],
    ['id' => 3, 'name' => 'Silveira', 'age' => '14', 'coffee' => 1],
    ['id' => 4, 'name' => 'Hubert', 'age' => '14', 'coffee' => 2],
    ['id' => 5, 'name' => 'Romano', 'age' => '16', 'coffee' => 4],
    ['id' => 6, 'name' => 'Antunes', 'age' => '12', 'coffee' => 1],
    ['id' => 7, 'name' => 'Castorino', 'age' => '18', 'coffee' => 2],
    ['id' => 8, 'name' => 'Pinson', 'age' => '17', 'coffee' => 1],
    ['id' => 9, 'name' => 'Finhane', 'age' => '20', 'coffee' => 3],
    ['id' => 10, 'name' => 'Santos', 'age' => '19', 'coffee' => 2]

foreach($devs as $key => $dev) {
    if($dev['coffee_a_day'] > 10) {
        $devs[$key]['coffee_a_day'] = 'gonna die';
    }
}
var_dump($devs);

O código acima funciona, mas o PHP possui aproximadamente 80 funções caixa preta para array que podem ter um ganho melhor em performance e gerenciamento de memória.

Esse mesmo código poderia ser reescrito da seguinte maneira:

array_map – Aplica uma função em todos os elementos do array

function god($dev)
{
    if ($dev['coffee_a_day'] > 10)
        $dev['coffee_a_day'] = 'gonna die';
    return $dev;
}

$god = array_map('god', $devs);

var_dump($god);

Podemos melhorar a escrita com função anônima:

$god = array_map(function($dev){
    if ($dev['coffee_a_day'] > 10)
        $dev['coffee_a_day'] = 'gonna die';
    return $dev;
}, $devs);

var_dump($god);

Apesar de parecer que estamos vendo tudo que o PHP faz quando usamos foreach() na verdade estamos vendo parcialmente. O PHP é escrito em C e foreach() não existe em C. Para entender o que acontece nos bastidores quando chamamos o foreach() acesse os links abaixo:

Aliás, vamos dar uma pausa e entender um pouco mais sobre o PHP.

A própria documentação do PHP diz que os exemplos apresentados em suas páginas são simples e não abrangem todo potencial do PHP. Em alguns casos a documentação pode estar ausente, incompleta ou errada. Por isso é interessante ter conhecimento suficiente do código-fonte C por trás do PHP.

Onde encontrar o código-fonte PHP?

A maneira mais fácil de baixar o código-fonte do PHP é no GitHub do PHP (https://github.com/php/php-src). Você pode baixar e abrir em um IDE para clicar e seguir funções, definições e etc. Mas se quiser apenas estudar, recomendo usar a ferramenta online que atende esse propósito: https://lxr.room11.org. Basicamente, é uma listagem pesquisável gerada automaticamente do código-fonte, que também é possível seguir funções, definições e etc.

O exemplo de código usado no inicio desse post onde substituímos o foreach() pelo array_map() é um bom exemplo de ser estudado e ver o que realmente acontece dentro dessa caixa preta.

A estrutura de pastas do código-fonte do PHP pode ser um pouco complicada de entender a primeira vista, mas você pode se concentrar inicialmente em duas pastas: ext e Zend. Todo o resto é importante para a execução e desenvolvimento do PHP.

O diretório Zend é o Mecanismo que alimenta o ambiente de execução em que nosso código PHP é executado. Ele lida com todos os recursos de “nível de linguagem” que o PHP fornece, incluindo: variáveis, instruções, análise de sintaxe, execução de código e tratamento de erros. Sem o mecanismo Zend não haveria PHP.

Na pasta ext estão as extensões incluídas no PHP. Estas extensões incluem todas as funções de um só núcleo que podemos chamar de PHP (tais como strpos, substr, array_diff, mysql_connect, etc.). Eles também incluem classes principais ( MySQLi, SplFixedArray, PDO, etc.).

Olha que legal: A documentação oficial do PHP é um bom lugar para identificar onde encontrar determinada função no código-fonte. A documentação é dividida em duas seções principais: Referência da Linguagem e a Referência da Função. Em termos gerais, se o que você procura está definido na Referência da Linguagem, é provável que seja encontrado na pasta Zend. Se estiver na Referência da Função, é provável que seja encontrado na pasta ext.

array_map internamente

Vamos até o código-fonte da versão 5.6 e pesquisar por array_map. Se você tentar buscar apenas por array_map na caixa de busca o resultado não vai ser animador pois resultará em vários registros de tests. Existe uma maneira melhor de fazer a pesquisa, digite “PHP_FUNCTION array_map” (não esqueça as aspas).

Agora temos apenas dois registros: php_array.h e array.c na pasta ext/standard. O arquivo com extensão .h é um arquivo de cabeçalho que contém uma lista simples das funções.

O arquivo array.c contém o código-fonte real das funções. Abra o arquivo e procure por PHP_FUNCTION(array_map) – lá pela linha 4166 – Entendendo de C ou tendo uma noção de programação você consegue identificar tudo que é feito dentro da função array_map do PHP.

Voltando…

Eu mostrei dois exemplos de como usar a função array_map(), com função anônima e chamada de função. Mas se você tentar usar a chamada de função dentro de uma classe se referenciando a um método dentro dessa classe, o código abaixo não vai funcionar:

class Foo
{
    public function god($v)
    {
        if ($v['coffee_a_day'] > 10)
            $v['coffee_a_day'] = 'gonna die';
        return $v;
    }

    public function init()
    {
        $devs = include 'devs.php';
        $test = array_map('god', $devs);

        var_dump($test);
    }
}

(new Foo())->init();

Para que o código acima funcione basta apontar o escopo da função com o $this:

$test = array_map([$this, 'god'], $devs);

Exemplo final:

class Foo
{
    public function god($v)
    {
        if ($v['coffee_a_day'] > 10)
            $v['coffee_a_day'] = 'gonna die';
        return $v;
    }

    public function init()
    {
        $devs = include 'devs.php';
        $test = array_map([$this, 'god'], $devs);

        var_dump($test);
    }
}

(new Foo())->init();

O array_map() foi usado para demonstrar o potencial das funções para arrays do PHP. Além dela também aconselho entender como funcionam as funções: array_filter(), array_reduce e array_walk();

Bons estudos!

Publicado por

Ricardo de Carvalho

Webmaster, Coordenador de Programação e Programador PHP, JS e React - certificado pela iMasters Certified Professional - PHP e JS - Boas práticas

Deixe uma resposta

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

Você pode usar estas tags e atributos de HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>