Php: класс для автоматического подключения файлов с нужными классами

12.06.2021

Бывает, что в проекте много классов, каждый их которых лежит в своем файле и код начинается с массы require или include.

В php давно существует несколько способов для автоматического подключения таких файлов.

Пожалуй самым известным является менеджер пакетов composer, но иногда его использование неприемлемо по той или иной причине.

Ниже приведу простой пример для решения данной задачи "своими руками".

Описание

Пример файловой структуры проекта:

/libs_1/controllers/item.php
/libs_1/controllers/items.php
/libs_1/models/item.php
/libs_1/models/items.php
/libs_1/test1.php
/libs_2/controllers/postController.php
/libs_2/controllers/postControllers.php
/libs_2/models/postModel.php
/libs_2/models/postModels.php

Пространство имен в для файлов из директорииlibs_1, в нашем примере, Oddler\Lib1 (namespace Oddler\Lib1;)

Для файлов из libs_2 - Oddler\Lib2.

Содержимое файлов одинаковое, для тестов, а разница в наименовании файлов, в первом случаи они не содержат тип в названии и именуются просто, например, item.php.
Во втором же случаи по названияю понятно, что это за файл тип файла, например, postController.php

Примеры использования

 
<?php

// Pre Init
error_reporting(E_ALL);
ini_set('display_errors', 'On');

// Init
require_once ('core/autoloader.php');
$oAutoloader = new soAutoloader();

// Test Lib 1 (file Name without Type)
$oAutoloader->setNamespace('Oddler\Lib1\\', 'libs_1');

$oItemController1 = new Oddler\Lib1\itemController();
echo $oItemController1->ping() . '<br />';

use Oddler\Lib1\itemModel;

$oItemModel1 = new itemModel();
echo $oItemModel1->ping() . '<br />';

$oTest1 = new Oddler\Lib1\test1();
echo $oTest1->ping() . '<br />';




// Test Lib 2 (file Name with Type)
$oAutoloader->setNamespace('Oddler\Lib2\\', 'libs_2');

$oItemController2 = new Oddler\Lib2\postController();
echo $oItemController2->ping() . '<br />';

$oItemModel2 = new Oddler\Lib2\postsModel();
echo $oItemModel2->ping() . '<br />';

Сам Autoloader

 
<?php

class soAutoloader {

    const DS = DIRECTORY_SEPARATOR;

    protected $_aTypes = [
        'controller' => 'controllers',
        'model' => 'models',
        'view' => 'views',
        'tool' => 'tools',
    ];

    protected $_aNamespaces = [];

    /**
     * Register loader with SPL autoloader stack.
     *
     * @return void
     */
    public function __construct()
    {
        spl_autoload_register(array($this, 'loadClass'));
    }

    public function setNamespace($sNamespace, $sDir)
    {
        $this->_aNamespaces[$sNamespace] = $sDir;
    }

    public function loadClass($sClass)
    {
        $sSubDir = '';
        $sNamespaceDir = '';
        $sFullClassName = '';
        $sClassName = $sClass;

        $pos = strrpos($sClass, '\\');
        if ($pos !== false) {
            $sNamespace = substr($sClass, 0, $pos + 1);
            $sClassName = substr($sClass, $pos + 1);
            foreach($this->_aTypes as $sType => $sTmpSubDir) {
                $pos2 = strpos(strtolower($sClassName), $sType);
                if ($pos2 !== false) {
                    $sSubDir = $sTmpSubDir;
                    $sFullClassName = $sClassName;
                    $sClassName = substr($sClassName, 0, $pos2);
                    break;
                }
            }

            if (isset($this->_aNamespaces[$sNamespace])) {
                $sNamespaceDir = $this->_aNamespaces[$sNamespace];
            }

//            echo $sNamespace .'<br />';
//            echo $sClassName .'<br />';
//            echo $sSubDir .'<br />';
        }

//        echo $sClass .'<br />';
//        echo $sNamespaceDir . ' ! ' . $sSubDir . ' ! ' . $sClassName . ' ! ' . '<br />';
//        echo $sNamespaceDir . ' ! ' . $sSubDir . ' ! ' . $sFullClassName . ' ! ' . '<br />';

        $sBasePath = $sNamespaceDir . self::DS . $sSubDir . self::DS;
        $sPath1 = $sBasePath . $sClassName . '.php';
        $sPath2 = $sBasePath . $sFullClassName . '.php';

        if (file_exists($sPath1)) {
            require_once ($sPath1);
        } elseif (file_exists($sPath2)) {
            require_once ($sPath2);
        }

    }
}

ToDo

Пока нельзя использовать USE Oddler\Lib1\ только полное название класса Oddler\Lib1\itemModel.


Категории: PHP, Class
Пометки: SoPhpAutoloader, Стандарт PSR-4 autoloader
Яндекс.Метрика