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.
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.
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:
Os namespaces da classe devem ser organizados da seguinte maneira:
\<Nome da biblioteca (Vendor) >\(<Namespace>)*\<Nome da Classe>
Os namespaces podem ter quantos níveis forem desejados mas o Vendor deve ser o primeiro nome.
Namespaces devem mapear a estrutura de diretórios. Cada separador de namespace ('\')
é convertido em uma constante DIRECTORY_SEPARATOR
para que a OS do sistema carregue o arquivo.
O nome de classe tem que ter sufixo com .php quando os arquivos forem carregados pelo o sistema.
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.
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
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).
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.