4 minutes to read, 7.75K views since 2017.01.06 Читать на русском Read in english

Автоматичний завантажувач класів

Підключення інших файлів в вашому сценарії

Коли ви пишете програму, яка складається з більш ніж одного файлу вам необхідно включити (include або require) файли за допомогою

include 'filename.php';
require 'another.php';

 Якщо ви використовуєте купу класів в вашому додатку вам потрібно щоб всі вони були проінклюжені в файл в якому ви їх використовуєте, це логічно. Коли класів багато, потрібно писати купу непотрібного коду вгорі сценарію який спотворює (це корректно, але не етично можна сказати) вашого коду

Ще одним мінусом явного включення файлу в ваш сценарій є те, що інтерпретатору мови прийдеться обробити включені файли і витратити на це час, навіть якщо насправді ви не використали класи які знаходяться в тих файлах

<?php

include_once 'some/library.php'; // SomeLibrary class

if ($userLogged) {
  $lib = new SomeLibrary();
  // do some stuff
} else {
  redirect_to('/');
}

У цьому сценарії файл some/library.php буде завжди аналізуватися PHP і зїдати оперативну пам'ять і процесорний час, навіть якщо користувач не увійшов в систему і перенаправляється на головну сторінку сайту.

 Таким чином, використання явного включення файлів не завжди є оптимальним рішенням. Звичайно, ви можете включити вашу бібліотеку тільки в тому випадку якщо користувач залоглен на сайті, проте це знову ж таки потворить ваш код:

<?php

if ($userLogged) {
  include_once 'some/library.php'; // SomeLibrary class
  $lib = new SomeLibrary();
  // do some stuff
} else {
  redirect_to('/');
}

Автоматичне завантаження відсутніх файлів

Ручне завантаження залежних файлів це добре, звичайно, але це не завжди виглядає елегантно, погодьтесь. Насправді, php має здатність включати файли автоматично: є магічна функція яка викликається коли клас, який використовується в скрипті не був знайдений в поточній області видимості. Це робиться за допомогою spl_autoload_register:

spl_autoload_register(function ($class) {
    // this function would be called when php would not find some $class 
});

Ви можете встановити функцію автозавантаження на початку вашої програми і забути про включення файлів після цього моменту. Spl_autoload_register приймає один параметр - функцію, яка повинна викликатися, коли якийсь клас не знайдений. Її параметр $ class матиме значення ім'я класу (включаючи простір імен) який не був знайдений:

"\Catchmetech\AutoloadingLesson\ExampleController"

Якщо ви будете правильно генерувати імена для класів в системі і розміщувати їх в потрібних папках, то автозавантаження вам здорово допоможе в подальшому.

Кращі практики ( PSR) говорять, що простір імен повинен відповідати шляху в файловій системі і кожен клас повинен бути в окремому файлі. Так, клас в наведеному вище прикладі повинен знаходитися в папці Catchmetech\AutoloadingLesson і повинен мати імя ExampleController.php. Звичайно, кожен клас повинен використовувати простір імен, як я вже згадував в попередніх уроках :)

Отже, як визначити, який файл я повинен включити в моїй функції автозавантаження? За допомогою str_replace замінимо в nemaspace роздільники в $class з правильним для нашої операційної системиDIRECTORY_SEPARATOR, додамо розширення файлу і вуаля:

$fileName = str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php';

Добре, у нас є шлях до файлу, але він відносний, так як ми використовували неймспейс класу для цього діла. Ми повинні додати до цього шляху префікс $baseDir який повинен відповідати абсолютному шляху до каталогу, де лежить наш додаток. Якщо ви правильно назвали класи і файли - все повинно працювати

$baseDir = __DIR__.'/'; 
$fileName = $baseDir.$fileName;

 Крім того, ми можемо перевірити, чи дійсно існує файл який ми шукаємо в файловій системі. Це можна зробити за допомогою is_file. У випадку якщо файл не існує - викидається exception:

spl_autoload_register(function ($class) {
    $base_dir = __DIR__.'/';

    $file = $base_dir . str_replace('\\',DIRECTORY_SEPARATOR, $class) . '.php';
    if (file_exists($file)) {
        require $file;
    } else {
        throw new \Exception ('can\'t include '.$file.PHP_EOL.' when trying to load `'.$class.'`');
    }
});

 Ось і все, ми зробили автоматичний завантажувач класів! Розмістіть код що вище, попередньо підлаштувавши його під себе, в верхній частині завантажувального файлу вашої програми і забудьте про купи include в файлах!

Read next article Working with relational database in php in course Basic PHP