A free and open-source book on ZF3 for beginners

Translation into this language is not yet finished. You can help this project by translating the chapters and contributing your changes.

3.4. Autoloading de Classes PHP

Uma aplicação web consiste em muitas classes PHP, e cada classe normalmente fica em um arquivo separado. Isso introduz a necessidade de incluir os arquivos.

Por exemplo, vamos supor que temos o arquivo chamado Application.php que contém a definição para a classe \Zend\Mvc\Application. Antes que você possa criar uma instância da classe Application em algum lugar do seu código, você tem que incluir o conteúdo do arquivo Application.php (você pode fazer isso com o ajuda do require_once, passando o caminho completo para o arquivo):

<?php
require_once "/path/to/zendframework/zend-mvc/src/Application.php";

use Zend\Mvc\Application;

$application = new Application();

Porém a medida que seu aplicativo for crescendo, pode ser difícil incluir cada arquivo necessário. O próprio Zend Framework 3 consiste em centenas de arquivos, e pode ser muito difícil carregar todas as bibliotecas e toda a sua dependências dessa maneira. Além disso, ao executar o código, o PHP levar tempo para processar cada arquivo, mesmo se você não criar um instância nenhuma classe.

Para corrigir esse problema, no PHP, o recurso de autoloading de classes foi introduzido. A função spl_autoload_register() permite que você registre uma função autoloader. Para sites complexos, você ainda pode criar várias funções do autoloader, que são encadeadas em pilha.

Durante a execução do script, se o PHP encontrar um nome de classe que ainda não foi definido, ele chama todas as funções de autoloader registradas, até que a função autoloader inclua a classe ou gere um erro "não encontrado". Isso permite o "lazy" loading, que é quando o PHP apenas processa a classe definição apenas no momento da invocação de classe, quando é realmente necessário.

3.4.1. Class Map Autoloader

Para ter uma ideia de como funciona uma função de autoloader, abaixo vamos apresentar uma implementação simplificada de uma função autoloader:

<?php
// Autoloader function.
function autoloadFunc($className) 
{
    // Class map static array.
    static $classMap = [
        '\\Zend\\Mvc\\Application' => '/path/to/zendframework/zend-mvc/src/Zend/Mvc/Application.php',
        '\\Application\\Module' => '/path/to/app/dir/module/Application/Module.php',
        //...
    ];

    // Check if such a class name presents in the class map.
    if(isset(static::$classMap[$className])) {
        $fileName = static::$classMap[$className];
  
        // Check if file exists and is readable.
        if (is_readable($fileName)) {
            // Include the file.
            require $fileName;
        }
    }
}

// Register our autoloader function.
spl_autoload_register("autoloadFunc");

No exemplo acima, nós definimos autoloadFunc() como uma função de autoloader, a qual nos referiremos a ela como class map autoloader.

O class map autoloader usa o class map para mapear entre o nome da classe e caminho absoluto para o arquivo PHP contendo essa classe. O class map é apenas um PHP normal array contendo chaves e valores. Para determinar o caminho do arquivo por nome de classe, class map autoloader só precisa buscar o valor do array. É óbvio que o autoloader do class map funciona muito rápido. No entanto, a desvantagem é que você tem que manter o class map atualizado e vai ter que você adicionar um novo classe para o seu programa toda vez que atualizá-lo.

3.4.2. Padrão PSR-4

Como cada biblioteca tem seu fornecedor e cada uma delas usa suas próprias convenções de código e organização de arquivos, você terá que registrar uma função autoloader diferente para cada biblioteca, o que é bastante irritante (e na verdade este é um trabalho desnecessário). Para resolver esse problema, o padrão PSR-4 foi introduzido.

PSR significa PHP Standards Recommendation..

O padrão PSR-4 define a estrutura de código recomendada que uma aplicação ou biblioteca deve seguir para garantir a interoperabilidade do autoloader. Em duas palavras, o padrão diz que:

Por exemplo, para a classe Zend\Mvc\Application, você terá a seguinte estrutura de pastas:

/path/to/zendframework/zend-mvc/src
  /Zend
    /Mvc
       Application.php

A desvantagem disso é que você precisa colocar seu código em vários pastas (Zend e Mvc).

Para corrigir isso, o PSR-4 permite que você defina que uma uma série de um ou mais de namespace e sub namespace corresponde a um "diretório base". Por exemplo, se você tiver o nome completo da classe \Zend\Mvc\Application e se você definir a série \Zend\Mvc corresponde ao diretório "/path/to/zendframework/zend-mvc/src", você pode organizar seus arquivos da seguinte forma:

/path/to/zendframework/zend-mvc/src
    Application.php

Para o código em conforme com o padrão PSR-4, podemos escrever e registrar um autoloader, ao qual nos referiremos como autoloader "padrão":

<?php

// "Standard" autoloader function.
function standardAutoloadFunc($className) 
{
    // Replace the namespace prefix with base directory.
    $prefix = '\\Zend\\Mvc';
    $baseDir = '/path/to/zendframework/zend-mvc/src/';
    if (substr($className, 0, strlen($prefix)) == $prefix) {
        $className = substr($className, strlen($prefix)+1);
        $className = $baseDir . $className;
    }

    // Replace namespace separators in class name with directory separators.
    $className = str_replace('\\', DIRECTORY_SEPARATOR, $className);
  
    // Add the .php extension.
    $fileName = $className . ".php";
  
    // Check if file exists and is readable.
    if (is_readable($fileName)) {
        // Include the file.
        require $fileName;
    } 
}

// Register the autoloader function.
spl_autoload_register("standardAutoloadFunc");

O padrão do autoloader funciona da seguinte maneira. Assumindo que a classe do namespace possa ser mapeado para a estrutura de diretórios um por um, a função calcula o caminho para o arquivo PHP, transformando back-slashes (separadores de namespace) em barras (separadores de caminho) e concatenando o caminho resultante com o caminho absoluto para o diretório no qual a biblioteca está localizada. Então o função verifica se tal arquivo PHP realmente existe, e se assim for, inclui com a declaração require.

É óbvio que o autoloader padrão funciona mais devagar que o class map autoloader. No entanto, sua vantagem é que você não precisa manter nenhum class map, o que é muito conveniente quando você desenvolve um novo código e adiciona novas classes sua aplicação.

Zend Framework 3 está dentro dos pardrões da PSR-4, tornando possível usar mecanismo de carregamento automático em todos os seus componentes. Também é compatível com outras blibiotecas que utilizam o padrão PSR-4 como o Doctrine ou o Symfony.

3.4.3. Composer-provided Autoloader

O Composer pode gerar funções de autoloader (mesmo padrão de carregament ode classes e padrão PSR-4) para o código que você instala com ele. O Zend Framework 3 usa a implementação do autoloader fornecida pelo Composer. Quando você instala um pacote com Composer, cria automaticamente o arquivo APP_DIR/vendor/autoload.php, que usa a função PHP spl_autoload_register() para registrar um autoloader. Desta forma todas as classes PHP localizado no diretório APP_DIR/vendor serão carregados automaticamente.

Para auto-carregar classes PHP do seus próprios módulos (como o módulo Application), você terá que especificar o autoload no seu arquivo composer.json:

"autoload": {
    "psr-4": {
        "Application\\": "module/Application/src/"
    }
},

Então, a única coisa que precisa ser feita é incluir esse arquivo no script de entrada do seu site index.php:

// Composer autoloading
include __DIR__ . '/../vendor/autoload.php';

O arquivo autoload.php é gerado toda vez que você instala um pacote com o Composer. Além disso, para faz o Composer gerar o arquivo autoload.php, você pode precisar executar o comando dump-autoload:

php composer.phar dump-autoload

3.4.4. PSR-4 e a Estrutura de origem do módulo

No Zend Skeleton Application, você pode ver como o padrão PSR-4 é aplicado na prática. Para o módulo padrão do seu site, o módulo Application, classes PHP que são registrados com o autoloader padrão são armazenados sob o APP_DIR/module/Application/src diretório (abreviação "src" significa "source (fonte)").

Vamos nos referir ao diretório src como o diretório de origem do módulo.

Por exemplo, vamos dar uma olhada no arquivo IndexController.php do módulo Application (imagem 3.2).

Imagem 3.2. Estrutura de pastas do skelleton application conforme o padrão PSR-4 Imagem 3.2. Estrutura de pastas do skelleton application conforme o padrão PSR-4

Como você pode ver, ele contém a classe IndexController 1 pertencente ao namespace Application\Controller. Para poder seguir o padrão PSR-4 e usar o autoloader padrão com esta classe PHP, temos que colocá-lo no diretório Controller dentro da pasta do módulo.

1) A classe IndexController é o controller padrão do skelleton application Vamos falar sobre controllers mais adiante no capítulo Model-View-Controller.


Top