O artigo será longo, então sente-se quando eu começar.
UPD: Como se viu, o método descrito neste artigo não ajuda em todos os casos - quando se trata de ORM, onde a nomeação de classes e arquivos é diferente (por exemplo, a classe ConfigTable, que está no arquivo config.php), problemas e erros começam. Portanto, ainda é melhor usar o Composer.
Então, Bitrix, ou melhor, Bitrix Framework. Apesar da presença de uma API avançada, de tempos em tempos é necessário criar suas próprias classes / bibliotecas, além de conectar outras de terceiros. Portanto, para começar, vejamos os métodos de carregamento automático existentes.
Os bons e velhos incluem / exigem. Eu o adicionei puramente para referência histórica. Embora no início do meu caminho de programação, coloquei as classes e bibliotecas necessárias em uma pasta separada, criei um arquivo separado onde incluí todas essas classes e só depois incluí o arquivo com as inclusões (peço desculpas pela tautologia).
Compositor.Permite conectar suas próprias classes e bibliotecas de terceiros. No entanto, ao adicionar novas classes, é necessária uma atualização manual. Além disso, as próprias classes, arquivos e espaços para nome também precisam ser gravados manualmente. Você pode ler sobre como fazer o Bitrix fazer amizade com um compositor aqui, no
Bitrix loader . É usado para conectar módulos e para carregar automaticamente classes. No entanto, antes de conectar as classes necessárias, você precisará formar uma matriz, onde as chaves serão os nomes das classes e os valores do caminho para elas. E tudo será algo como isto:
$classes = [
'Namespace\\Package\\ClassName' => '/path/to/class.php'
];
Loader::registerAutloadClasses(null, $classes);
Módulos personalizados. Eles dizem que esta é a maneira mais recomendada - você cria um módulo, instala-o na área de administração, conecta-o em qualquer lugar e usa-o para seu prazer. Parece simples, mas, na realidade, temos o seguinte:
- Além de escrever aulas, você também precisa registrar o procedimento para instalar e remover o módulo. Existem vários parâmetros e métodos necessários, sem os quais o módulo pode não funcionar (embora eu não saiba, ainda não o testei)
- As aulas não funcionarão sem conectar o módulo
- Nem sempre faz sentido mover uma classe para um módulo separado
No entanto, se você escreveu seu módulo local e decidiu adicionar mais algumas classes a ele, para usá-lo, não é mais necessário reinstalar o módulo - basta chamar os métodos necessários no lugar certo, e é isso!
Bem, agora, de fato, a bicicleta em si ...
Depois de analisar todos os métodos acima, pensei sobre o que criar para que fosse suficiente adicionar novas classes a um determinado local e elas fossem carregadas automaticamente, sem adicionar novos elementos à matriz de espaços para nome e caminhos de arquivo.
Como resultado, decidiu-se escrever um módulo especial - por mais estranho que possa parecer, mas essa idéia me pareceu mais bem-sucedida do que adicionar algumas funções ao init.php - que carregará automaticamente todas as classes do diretório necessário.
Eu omitirei o processo de escrever a instalação / remoção de um módulo - quem precisar, ele procurará a fonte e passará diretamente para a funcionalidade principal.
Porque inicialmente, o número de níveis de aninhamento de pastas é desconhecido; os métodos precisam ser recursivos. Também usaremos a classe Bitrix \ Main \ Loader, que carregará as classes.
Vamos imaginar que decidimos colocar todas as nossas classes no diretório / local / php_interface / lib:
Também podemos ter arquivos que não contêm classes e, portanto, não devem ser incluídos no carregador automático, portanto, esse ponto também deve ser levado em consideração.
Então vamos.
namespace Ramapriya\LoadManager;
use Bitrix\Main\Loader;
class Autoload
{
}
Primeiro de tudo, precisamos obter todo o conteúdo da nossa pasta. Para fazer isso, vamos escrever o método scanDirectory:
public static function scanDirectory(string $dir) : array
{
$result = [];
$scanner = scandir($dir); //
foreach ($scanner as $scan) {
switch ($scan) {
//
case '.':
case '..':
break;
default:
//
$item = $dir . '/' . $scan;
$SplFileInfo = new \SplFileInfo($item);
if($SplFileInfo->isFile()) {
// ,
$result[] = $scan;
} elseif ($SplFileInfo->isDir()) {
// ,
$result[$scan] = self::scanDirectory($item, $result[$scan]);
}
}
}
return $result;
}
A saída deve ser a seguinte:
Como podemos ver, a estrutura do arquivo é respeitada, para que você possa começar a formar uma matriz para carregamento automático:
/* $defaultNamespace, .
php-,
*/
public static function prepareAutoloadClassesArray(string $directory, string $defaultNamespace, array $excludeFiles) : array
{
$result = [];
//
$scanner = self::scanDirectory($directory);
foreach ($scanner as $key => $value) {
$sep = '\\';
switch(gettype($key)) {
case 'string':
// ,
$SplFileInfo = new \SplFileInfo($directory . '/' . $key);
$classNamespace = $defaultNamespace . $sep . $key;
if($SplFileInfo->isDir()) {
// , , , ,
$tempResult = self::prepareAutoloadClassesArray($directory . '/' . $key, $classNamespace, $excludeFiles);
foreach($tempResult as $class => $file) {
//
$result[$class] = $file;
}
}
break;
case 'integer':
// - ,
$SplFileInfo = new \SplFileInfo($directory . '/' . $value);
// ( , )
$classNamespace = $defaultNamespace . $sep . str_ireplace('.php', '', $SplFileInfo->getBasename());
// php-
if(
$SplFileInfo->isFile() &&
$SplFileInfo->getExtension() === 'php'
) {
// ,
foreach($excludeFiles as $excludeFile) {
if($SplFileInfo->getBasename() !== $excludeFile) {
//
$result[$classNamespace] = str_ireplace($_SERVER['DOCUMENT_ROOT'], '', $directory . '/' . $value);
}
}
}
break;
}
}
return $result;
}
Se tudo for feito corretamente, no final obteremos uma matriz gerada para carregamento automático usando um carregador bitrix:
Para verificar a funcionalidade, adicione o arquivo MainException.php à pasta com exceções que contêm a seguinte classe:
<?php
namespace Ramapriya\Exceptions;
class MainException extends \Exception
{
public function __construct($message = null, $code = 0, Exception $previous = null)
{
parent::__construct($message, $code, $previous);
}
}
Como podemos ver, nosso arquivo foi carregado em uma matriz de classes:
Olhando para o futuro, vamos tentar chamar nossa nova exceção:
throw new Ramapriya\Exceptions\MainException('test exception');
Como resultado, veremos:
[Ramapriya\Exceptions\MainException]
test exception (0)
Portanto, resta implementar o método de carregamento automático para a matriz resultante. Para esse fim, escreveremos um método com o nome mais banal loadClasses, onde passaremos a matriz resultante:
public static function loadClasses(array $classes, $moduleId = null)
{
Loader::registerAutoloadClasses($moduleId, $classes);
}
Este método usa um carregador bitrix, que registra uma matriz com nossas classes.
Agora, resta muito pouco - formar uma matriz com classes e carregá-las usando a classe que escrevemos. Para fazer isso, em nossa pasta lib, crie um arquivo include.php:
<?php
use Bitrix\Main\Loader;
use Bitrix\Main\Application;
use Ramapriya\LoadManager\Autoload;
// - ,
Loader::includeModule('ramapriya.loadmanager');
$defaultNamespace = 'Ramapriya';
$excludeFiles = ['include.php'];
$libDir = Application::getDocumentRoot() . '/local/php_interface/lib';
$autoloadClasses = Autoload::prepareAutoloadClassesArray($libDir, $defaultNamespace, $excludeFiles);
Autoload::loadClasses($autoloadClasses);
Em seguida, vamos incluir este arquivo no init.php:
// init.php
$includeFile = $_SERVER['DOCUMENT_ROOT'] . '/local/php_interface/lib/include.php';
if(file_exists($includeFile)) {
require_once $includeFile;
}
Em vez de uma conclusão
Bem, parabéns, nossa bicicleta está pronta e faz um excelente trabalho com sua função.
As fontes estão, como sempre, no github .
Agradecimentos para sua atenção.