php spl autoload register namespace

Неймспейсы и автозагрузка в PHP

В этом уроке мы коснемся архитектуры приложений. Если быть точнее – мы научимся тому, как в современном программировании на PHP принято хранить классы в отдельных файлах, и о том, как избегать при этом бесконечных строчек с include и require для подключения этих файлов.

На самом деле, в PHP всё довольно просто с правилами по реализации большинства частей приложения. Для этого есть уже придуманные умными людьми стандарты – PSR (PHP Standards Recommendations). В них описано, как нужно писать ту или иную составляющую вашей программы.

В этом уроке мы затронем стандарт PSR-4. В нём говорится о том, что каждый класс должен храниться в отдельном файле и находиться в пространстве имён. Давайте обо всём по порядку.

Пусть у нас есть классы User и Article. Нам нужно сохранить их в разных файлах. Для этого давайте создадим рядом с папкой www папку src, а внутри неё папку MyProject. Внутри папки MyProject создадим папку Models, а в ней создадим ещё 2 папки – Articles и Users. И уже в этих папках создадим файлы Article.php и User.php. Должно получиться следующее:

php spl autoload register namespace. Смотреть фото php spl autoload register namespace. Смотреть картинку php spl autoload register namespace. Картинка про php spl autoload register namespace. Фото php spl autoload register namespace

Давайте теперь опишем в этих двух файлах наши классы.
src/MyProject/Models/Articles/Article.php

Первую часть сделали – теперь у нас каждый класс лежит в отдельном файле. Давайте теперь перейдём в наш index.php, лежащий в директории www и запишем в него логику для работы с этими классами.

Давайте теперь попробуем запустить этот скрипт в браузере.
Разумеется, мы получим ошибку.

php spl autoload register namespace. Смотреть фото php spl autoload register namespace. Смотреть картинку php spl autoload register namespace. Картинка про php spl autoload register namespace. Фото php spl autoload register namespace

Нашему скрипту не удалось найти класс User. Давайте подключим файлы с нужными нам классами в начале index.php

Если мы сейчас запустим этот скрипт, то всё у нас прекрасно отработает и мы увидим результат var_dump().

php spl autoload register namespace. Смотреть фото php spl autoload register namespace. Смотреть картинку php spl autoload register namespace. Картинка про php spl autoload register namespace. Фото php spl autoload register namespace

Итак, с первым пунктом про хранение классов в отдельных файлах мы разобрались.

Теперь вернёмся к пространствам имён – неймспейсам. Тут всё довольно просто – класс можно поместить в отдельное именованное пространство и в дальнейшем использовать его по этому полному имени. Для того чтобы указать это пространство для конкретного класса используется слово namespace, за которым следует само имя. Указывается оно в файле с классом, перед определением класса. На примере класса User это будет выглядеть следующим образом:
src/MyProject/Models/Users/User.php

Теперь мы можем говорить, что класс User находится в неймспейсе MyProject\Models\Users.

Давайте проделаем аналогичные действия с классом Article.
src/MyProject/Models/Articles/Article.php

Теперь, чтобы в файле index.php работать с данными классами, мы должны указать полное имя класса – это имя класса с указанием его неймспейса. Делается это следующим образом.
www/index.php

Если мы сейчас запустим скрипт, то снова столкнёмся с ошибкой.

php spl autoload register namespace. Смотреть фото php spl autoload register namespace. Смотреть картинку php spl autoload register namespace. Картинка про php spl autoload register namespace. Фото php spl autoload register namespace

Но на этот раз, она уже другая. А именно – третий аргумент, переданный в конструктор класса Article должен быть объектом класса MyProject\Models\Articles\User, а передан объект класса MyProject\Models\Users\User. Заметили ошибку? Неймспейс не тот. Дело в том, что если в файле с классом указан неймспейс, то все классы, которые указываются в данном файле будут искаться в том же неймспейсе. Так как у нас класс User находится в другом неймспейсе, то мы должны явно это указать. Вот так:
src/MyProject/Models/Articles/Article.php

Либо же указать в начале файла о каком классе идёт речь, когда мы используем в коде только слово User. Делается это с помощью слова use после указания текущего неймспейса, но перед описанием класса.

Теперь, когда мы будем использовать класс User, то автоматически будет использоваться класс из неймспейса MyProject\Models\Users\User.

Давайте снова запустим скрипт, и убедимся, что всё у нас теперь работает.

Получили работающий скрипт. Ура! Вот в принципе и всё, что вам нужно знать о неймспейсах. В наших будущих программах мы всегда будем создавать классы внутри неймспейсов.

Автозагрузка

Однако, давайте снова посмотрим на наш файл index.php. представьте, что у нас теперь большой проект и в нём больше 100 классов. Нам придётся сто раз писать require с указанием каждого файла. Утомительно, да? Однако, можно автоматизировать этот процесс, написав функцию автозагрузки классов. Она будет вызываться каждый раз, когда впервые будет встречаться новый класс.

Итак, давайте сделаем эту функцию автозагрузки. Давайте я сначала приведу пример кода, а затем объясню, как это работает. Наш файл index.php принимает следующий вид:

А теперь по порядку о том, что же происходит.

Всё! Теперь все классы будут подгружаться автоматически. Давайте запустим скрипт и убедимся, что всё работает.

Снова запустим скрипт и посмотрим на вывод.

Мы видим, что в эту функцию попал сначала класс MyProject\Models\Users\User, а затем MyProject\Models\Articles\Article. И для этих классов мы сделали require нужных файлов и они успешно подгрузились.

На этом давайте var_dump уберём.

В функцию spl_autoload_register можно и вовсе передать не имя функции, а прямо саму функцию – не будем сейчас на этом останавливаться более детально. Просто знайте, что так можно:

В таком случае, функция называется анонимной – у неё нет имени. Она просто передаётся в качестве аргумента и имя ей не нужно.

Запустите код ещё раз, и убедитесь, что всё работает как нужно.
Вот такими вот нехитрыми действиями мы сделали автозагрузку классов. PHP – прекрасный язык, не правда ли?

Начиная с текущего урока я решил выкладывать итоговые результаты уроков на github, чтобы вам в случае чего можно было свериться с кодом, который должен был получиться в конце урока. Вот ссылка на результат этого урока.

Источник

Об автозагрузке в PHP

При написании приложений, код размещают в отдельных файлах. Чтобы код одного файла использовать в другом, его необходимо подключить через функцию require_once или include_once

Времена до автозагрузки

До PHP 5.0 (2005 г.) использовались подключение файлов через многократные вызовы фукнций require_once

Магический метод __autoload

Данный метод объявлен УСТАРЕВШИМ начиная с PHP 7.2.0 и его использование крайне не рекомендовано.

Уже при этом подходе здравый смысл подсказывал, что в одном файле должен находится один класс, а название класса должно совпадать с названием файла.

В PHP 5.1.2 (2006 г.) эти проблемы решили через фукнции автозагрузчики.

Автозагрузка через spl_autoload_register

PHP позволяет зарегистрировать любое число функций-автозагрузчиков с помощью функции spl_autoload_register. В случае обращения к несуществующему в данный момент классу, PHP будет вызывать по очереди все зарегистрированные автозагрузчики, передавая им имя класса. Если автозагрузчик знает, где лежит этот класс, он должен подключить файл с ним, PHP увидит, что класс появился, и продолжит выполнение программы. Иначе PHP вызовет следующий автозагрузчик. Если ни один автозагрузчик не подключит файл с классом, то будет выведена ошибка об обращении к несуществующему классу.

Если подключается сторонняя библиотека, то она может зарегистрировать свой автозагрузчик для загрузки своих классов. Таким образом, каждая библиотека может устанавливать свои правила для поиска файлов со своими классами.

Есть fallback для __autoload :

Автозагрузка через composer и PSR-4

Развитием идеи в одном файле один класс стал стандарт PSR-0 (англ.) (устаревший) и его развитие PSR-4 (англ.). PSR-4 говорит как надо называть классы, чтобы по полному имени класса узнать путь к файлу (чтобы потом его подключил автозагрузчик).

Пример пакета foo-bar по PSR-4

На сегодняшний день большинство PHP разработчиков пользуются загручиком из менеджера зависимостей Сomposer. Composer не является только лишь генератором автозагрузчика. Задачи, которые он выполняет намного шире.

Генерация и использование автозагрузчика из composer

Пример раздела в файле composer.json говорящий, что классы из namespace’a Foo находятся в папке src, а классы из App\Plugins надо искать в plugins/.

Соответственно классы будут искаться так:

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

или при установленном composer

Команда сгенерирует файлы автозагрузчика и положит их в папку vendor. После этого надо подключить автозагрузчик в свои файлы и наслаждаться программированием.

Таким образом, следование PSR-4 и использование composer позволяет не писать свой автозагрузчик.

Источник

spl_autoload_register

(PHP 5 >= 5.1.0, PHP 7, PHP 8)

spl_autoload_register — Регистрирует заданную функцию в качестве реализации метода __autoload()

Описание

Регистрирует функцию __autoload в предоставляемой SPL очереди. В результате очередь будет активирована, даже если ранее она была выключена.

spl_autoload_register() позволяет задать несколько реализаций метода автозагрузки. Она создаёт очередь из функций автозагрузки в порядке их определения в скрипте, тогда как встроенная функция __autoload() может иметь только одну реализацию.

Список параметров

Этот параметр определяет, должна ли spl_autoload_register() выбрасывать исключение, если зарегистрировать callback оказалось невозможным.

Если передано значение true, spl_autoload_register() поместит указанную функцию в начало очереди вместо добавления в конец.

Возвращаемые значения

Возвращает true в случае успешного выполнения или false в случае возникновения ошибки.

Список изменений

ВерсияОписание
8.0.0callback теперь допускает значение null.

Примеры

Пример #1 spl_autoload_register() как альтернатива функции __autoload()

Пример #2 Пример использования spl_autoload_register() в случае, если класс не загрузился

Результатом выполнения данного примера будет что-то подобное:

Смотрите также

User Contributed Notes 28 notes

Good news for PHP 5.3 users with namespaced classes:

When you create a subfolder structure matching the namespaces of the containing classes, you will never even have to define an autoloader.

( «.php» ); // comma-separated list
spl_autoload_register ();
?>

It is recommended to use only one extension for all classes. PHP (more exactly spl_autoload) does the rest for you and is even quicker than a semantically equal self-defined autoload function like this one:

To load and instantiate these 1000 classes (parameterless no-action constructor), the user-definded autoload function approach took 50ms longer in average than the spl_autoload function in a series of 10 command-line calls for each approach.

I made this benchmark to ensure that I don’t recommend something that could be called «nice, but slow» later.

Even when autoloading (SPL) is used, class inheritance does not seem to work. Simply the PHP engine is unable to find parent (inherited) class. PHP 5.6 and 7.0 behave exactly same on this, which beats the purpose of autoloading.

And IMHO it’s easy to fix as the autoloader is able to find all first level classes w/o problems, it just needs to follow same path recursively on parents too.

//Using default SPL autoloader, with namespaces mapping 1:1 to directory structure, with file names being all lowercase.
//This works with first level classes only, for inheritance it does NOT work, it cannot find parent classes.
spl_autoload_register ();

When switching from using __autoload() to using spl_autoload_register keep in mind that deserialization of the session can trigger class lookups.

$autoloader = new ClassAutoloader ();

$obj = new Class1 ();
$obj = new Class2 ();

?>

Output:
———
Trying to load Class1 via ClassAutoloader::loader()
Class1::__construct()
Trying to load Class2 via ClassAutoloader::loader()
Class2::__construct()

If your autoload function is a class method, you can call spl_autoload_register with an array specifying the class and the method to run.

Think twice about throwing an exception from a registered autoloader.

If you have multiple autoloaders registered, and one (or more) throws an exception before a later autoloader loads the class, stacked exceptions are thrown (and must be caught) even though the class was loaded successfully.

What I said here previously is only true on Windows. The built-in default autoloader that is registered when you call spl_autoload_register() without any arguments simply adds the qualified class name plus the registered file extension (.php) to each of the include paths and tries to include that file.

Example (on Windows):

include paths:
— «.»
— «d:/projects/phplib»

qualified class name to load:
network\http\rest\Resource

Here’s what happens:

PHP tries to load
‘.\\network\\http\\rest\\Resource.php’
-> file not found

PHP tries to load
‘d:/projects/phplib\\network\\http\\rest\\Resource.php’
-> file found and included

Note the slashes and backslashes in the file path. On Windows this works perfectly, but on a Linux machine, the backslashes won’t work and additionally the file names are case-sensitive.

That’s why on Linux the quick-and-easy way would be to convert these qualified class names to slashes and to lowercase and pass them to the built-in autoloader like so:

I prefer the lowercase approach, because it is easier to use and the file name conversion can be done automatically on deploying.

Be careful using this function on case sensitive file systems.

( ‘.php’ );
spl_autoload_register ();
?>

I develop on OS X and everything was working fine. But when releasing to my linux server, none of my class files were loading. I had to lowercase all my filenames, because calling a class «DatabaseObject» would try including «databaseobject.php», instead of «DatabaseObject.php»

I think i’ll go back to using the slower __autoload() function, just so i can keep my class files readable

It is never a good idea and a unconscienable concept to create the classes in the autoload function via eval.
It should be a nice feature with these Exception, but i think anyone is able to handle it without this method although. Atm i dont realize for what this is good for.

It is important to note that the autoloader will NOT be called if an E_STRICT error triggers the error handler which, in turn, tries to use classes which are not yet loaded.

In this instance, you should manually load classes required by the error handler.

A note on registering autoloading functions with additional parameters.

It seems, that spl_autoload tests, if the class exists, after calling every registered loader. So it breaks the chain, if the class exists and will not call the other loaders

if you have a dir-structure like «/abc/def/ghi», your index.php lies in the top directory, but you want to use namespaces starting with «def» or «ghi»:

remember that php handlers «cli» and «cli-server» are special cases.

The spl_autoload_register() method registers functions in its stack in the order that spl_autoload_register() was called, and subsequently if you want an autoload function to override previous autoload functions you will either need to unregister the previous ones or change the order of the autoload stack.

For example, say in your default implementation of an autoload function you throw an exception if the class cannot be found, or perhaps a fatal error. Later on in your code you add a second implementation of an autoload function which will load a library that the previous method would fail on. This will not call the second autoloader method first, but rather will continue to error out on the first method.

As previously mentioned, you can unregister the existing autoloader that errors out, or you can create a mechanism for unregistering and re-registering the autoloaders in the order you want.

Here is a sample/example of how you might consider re-registering autoloaders so that the newest autoloader is called first, and the oldest last:

// Editorial notes: Small bug and compatibility fixes
// added to the function

?>

Note: I have not tested this for overhead, so I am not 100% sure what the performance implication of the above example are.

Источник

spl_autoload

(PHP 5 >= 5.1.0, PHP 7, PHP 8)

spl_autoload — Реализация по умолчанию метода __autoload()

Описание

Список параметров

Имя класса (и пространства имён) в нижнем регистре, которое требуется загрузить.

Возвращаемые значения

Функция не возвращает значения после выполнения.

Ошибки

Список изменений

ВерсияОписание
8.0.0file_extensions теперь допускает значение null.

User Contributed Notes 9 notes

Note, that the default autoload implementation is written in C land and is always slightly faster then your native PHP one.

Here is a trick to use default implementation with any configuration:

// You can use this trick to make autoloader look for commonly used «My.class.php» type filenames
spl_autoload_extensions ( ‘.class.php’ );

// Use default autoload implementation
spl_autoload_register ();
?>

This also works with namespaces out of the box. So you can write code like «use My\Name\Object» and it will map to «class/My/Name/Object.class.php» file path!

If you want to make the best use out of autoload with an APC cache don’t use spl_autoload. It uses relative paths and thus will perform a stat even with apc.stat=0 (either that, or it doesn’t work at all).

Instead make a custom function and use require/include with an absolute path (register it with spl_autoload_register).

Do NOT use *_once functions or a relative path. This will fail harder than spl_autoload.

Also avoid using file_exists and is_file. This will also perform a stat.

Why are stats bad? Because they access the file system. PHP does have a stat cache that helps, but it defeats the purpose of apc.stat = 0.

It’s also good to keep in mind that it’s good to keep your custom autoload function simple. This is my Loader class:

?>

Also want to point out that APC does an optimization with require/include (not *_once) with relative paths if require/include is done in the global scope (and isn’t conditional). So it would be a good idea to explicitly include files you know you’re going to use on every request (but don’t use *_once). You could, for example, add a «registerProfiledAutoload» to the above class and keep track of what you’re including to help you determine what you could explicitly include (during development, not production). The key is try not to make heavy use out of autoload.

If you must use relative paths and don’t care about having to lower-case your file-names then spl_autoload works great.

Note that, the orders of file extensions is important for performance. You should make the priority of your favourite file extension higest or use only one extension for your class files. Check out this example:

Just thought I’d react to simast at gmail dot com’s note: While he has a point in saying C outperforms PHP, his suggestion is micro-optimization. I’m not 100% against micro-optimizing code, but if you do, go all the way:

set_include_path(
CLASS_DIR.
PATH_SEPARATOR,
get_include_path()
);

Note this function will LOWERCASE the class names its looking for, dont be confused when it cant find Foo_Bar.php

also, unlike most other autoloader code snippets, this function DOES NOT translate underscores to slashes.

class Foo_Bar <>
will load foo_bar.php and will not try to load foo/bar.php

One small example that shows how you can use spl_autoload function in your MVC, Framewrk’s applications. For example, will use the Loader class.

/**
* Constructor
* Constant contain my full path to Model, View, Controllers and Lobrary-
* Direcories.
*
* @Constant MPATH,VPATH,CPATH,LPATH
*/

Источник

How do I use PHP namespaces with autoload?

I get this error when I try to use autoload and namespaces:

Fatal error: Class ‘Class1’ not found in /usr/local/www/apache22/data/public/php5.3/test.php on line 10

Can anyone tell me what I am doing wrong?

php spl autoload register namespace. Смотреть фото php spl autoload register namespace. Смотреть картинку php spl autoload register namespace. Картинка про php spl autoload register namespace. Фото php spl autoload register namespace

13 Answers 13

Class1 is not in the global scope.

Note that this is an old answer and things have changed since the days where you couldn’t assume the support for spl_autoload_register() which was introduced in PHP 5.1 (now many years ago!).

These days, you would likely be using Composer. Under the hood, this would be something along the lines of this snippet to enable class autoloading.

For completeness, here is the old answer:

To load a class that is not defined in the global scope, you need to use an autoloader.

or without aliases:

php spl autoload register namespace. Смотреть фото php spl autoload register namespace. Смотреть картинку php spl autoload register namespace. Картинка про php spl autoload register namespace. Фото php spl autoload register namespace

As mentioned Pascal MARTIN, you should replace the ‘\’ with DIRECTORY_SEPARATOR for example:

Also I would suggest you to reorganize the dirrectory structure, to make the code more readable. This could be an alternative:

Your __autoload function will receive the full class-name, including the namespace name.

This means, in your case, the __autoload function will receive ‘ Person\Barnes\David\Class1 ‘, and not only ‘ Class1 ‘.

I do something like this: See this GitHub Example

I see that the autoload functions DO NOT receive the full classname in the following case:

UPDATE: [c] is a mistake and isn’t how namespaces work anyway. I can report that, instead of [c], the following two cases also work well:

php spl autoload register namespace. Смотреть фото php spl autoload register namespace. Смотреть картинку php spl autoload register namespace. Картинка про php spl autoload register namespace. Фото php spl autoload register namespace

php spl autoload register namespace. Смотреть фото php spl autoload register namespace. Смотреть картинку php spl autoload register namespace. Картинка про php spl autoload register namespace. Фото php spl autoload register namespace

I found this gem from Flysystem

I use this simple hack in one line:

had the same issue and just found this :

When you create a subfolder structure matching the namespaces of the containing classes, you will never even have to define an autoloader.

It worked like a charm

EDIT: this causes problem on Linux because of backslash. See here for working solution by immeëmosol

Using has a gotcha, while it is by far the fastest method, it also expects all of your filenames to be lowercase.

A file containing the class SomeSuperClass would need to be named somesuperclass.php, this is a gotcha when using a case sensitive filesystem like Linux, if your file is named SomeSuperClass.php but not a problem under Windows.

Using __autoload in your code may still work with current versions of PHP but expect this feature to become deprecated and finally removed in the future.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *