php spl autoload extensions
spl_autoload
(PHP 5 >= 5.1.0, PHP 7, PHP 8)
spl_autoload — Default implementation for __autoload()
Description
Parameters
The lowercased name of the class (and namespace) being instantiated.
Return Values
No value is returned.
Errors/Exceptions
Throws LogicException when the class is not found and there are no other autoloaders registered.
Changelog
Version | Description |
---|---|
8.0.0 | file_extensions is now nullable. |
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
*/
Предисловие переводчика
Данная статья является вольным переводом-пересказом поста The End of Autoloading
. Оригинальная статья не первой свежести, поэтому код приведенный в примерах может быть не актуален. В теме, которую затрагивает статья, самое главное — общий взгляд, а не конкретные примеры.
Предисловие
Автозагрузка в PHP отлично экономит время. Это позволяет писать скрипты не задумываясь о путях к библиотекам, которые вы используете. Но с приходом неймспейсов и под влиянием Java-стиля современных фреймворков ситуация изменилась. В ближайшем будущем автозагрузка будет повсеместно, но без единой выгоды старого ее стиля.
До автозагрузки. Пути к файлам.
До появления автозагрузки, в каждом скрипте необходимо было указывать пути к используемым библиотекам. Исходный код выглядел так:
Зависимости явно прописывались в начале каждого скрипта. В этом примере зависимость очевидна, даже если вызов PEAR_DependencyDB находится на 328 строке.
Приход SPL-автозагрузки.
Позже появилась функция spl_autoload_register(), позволившая убрать вызовы require/require_once. Замечательным было то, что теперь появилась возможность использовать классы без необходимости знания где они расположены. Например:
Смотрите, здесь нет ни единого вызова require/require_once, при том, что этот класс зависим от sfActions, PostPeer, и Criteria классов. Разработчики смогли заниматься бизнес-логикой, не тратя время на поиск путей зависимостей. Это было действительно удобно.
Реализации автозагрузки.
Реализации автозагрузки варьируются. Некоторые библиотеки используют список всех классов, которые нужно подключить. Например:
Эта техника позволила скрыть пути к классам, но заставила разработчика библиотеки обновлять “карту” автозагрузки, каждый раз, при добавлении нового класса. Другая техника использует проход по структуре папок проекта в поиске нужного класса. Такой подход позволил подменять классы фреймворка своими, т.к. проход по папкам происходил в определенном порядке: пользовательские папки, проекта, плагинов и фреймворка. Таким образом разработчик мог создать класс ClassName, который подменит ClassName предоставленный плагином, т.к. загрузится раньше.
Автозагрузка с неймспейсами
Приход неймспейсов изменил техники автозагрузки. Авторы фреймвроков объединились, что бы унифицировать техники автозагрузки, для возможности технического взаимодействия между различными библиотеками. Было решено, что явное лучше неявного и полное имя класса будет относительным путем к файлу.
Были выработаны принципы именования и файловой структуры, а также реализация класса SplClassLoader. Этот подход сейчас используется практически во всех современных фреймворках. Пример кода:
Здесь все также нет require благодаря автозагрузке. Автозагрузчик ищет Symfony\Framework\WebBundle\Controller класс в файле Symfony/Framework/WebBundle/Controller.php.
Все хорошо, все довольны. Зависимости явные и подмена класса происходит легко:
Конец все удобствам.
Использование use в предыдущем примере вам ничего не напоминает? Это ведь очень похоже на старый добрый require/require_once, не так ли?
Привнесенная неймспейсами многословность в первую очередь снижает легкость использования автозагрузки. Но проблема не только в том, что нужно писать больше кода, в этом вам может помочь IDE с автодополнением, а в том, что вам нужно знать полные имена нужных вам классов. Вы должны очень хорошо знать классы фреймворка, чтобы использовать их. Это шаг назад по сравнению с автозагрузкой “первого поколения”, где было достаточно знать имя класса.
Другого пути нет.
Правда было бы замечательно, использовать современные библиотеки без знания их файловой структуры? Что если бы вы могли написать контроллер так:
Умный автозагрузчик перехватил бы вызов класса Controller, загрузил бы файл Symfony/Framework/WebBundle/Controller.php и динамически создал алиас с Symfony\Framework\WebBundle\Controller на Controller. К сожалению в PHP use создает алиас во время компиляции, поэтому такой ход не сработает. Конечно есть возможность сделать подобное используя eval, но это, наверное, даже хуже, чем подключать файлы вручную. Также создание таких алиасов при работе с фреймворком не возможно по причине конфликта с ленивой загрузкой и конфликта имен классов, например:
Symfony\Framework\WebBundle\Command
и
Symfony\Components\Console\Command\Command
Пока авторы фреймворков не изменят свой взгляд на автозагрузку, будущее PHP мне видится многословным.
Решение проблемы.
Лично я, думаю, что многословность сильно замедляет разработку. Например возьмем микрофреймворки – они дают возможность обработать запрос быстро, при минимуме MVC-разделения. Сравним код примерного приложения написанного с использованием Slim (автозагрузка без неймспейсов) и Silex (автозагрузка с неймспейсами):
Во втором примере, автозагрузка делает все только сложнее.
Разработчики современных фреймворков объясняют, что многословность – это цена, которую мы платим за качество кода. Я не уверен, что хочу платить эту цену. Я не хочу видеть как PHP превращается в Java, где код превосходен с точки зрения Computer Science, но очень затратен в написании. Это побуждает желание к использованию других языков, где вопрос автозагрузки с неймспейсами не стоит и при этом, быстрая разработка возможна.
Возьмем например Ruby. Существует такой фреймворк как Sinatra, используя который HelloWorld-приложение становится очень лаконичным:
Ой, смотрите, здесь же используется require! И при этом, все пишется очень быстро и легко в использовании.
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.0 | callback теперь допускает значение 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.
Автоматическая загрузка классов в PHP с использованием spl_autoload.
Всем привет. В этой статье я расскажу про автоматическое подключение файлов в php с помощью spl_autoload.
На сайте уже была статья про магический метод __autoload, который делал то же самое, однако из-за своих недостатков он достаточно быстро устарел. А на смену ему пришла функция spl_autoload. Вот давайте о ней и поговорим.
Внутрь функции spl_autoload_register вы можете передать анонимную, или лямбда функцию, которая будет что-то делать, например, подключать файлы.
Также, вы можете вынести эту функцию отдельно, а в spl_autoload_register передать строковое значение с названием вашей функции.
С помощью spl_autoload_extensions вы можете указать значения расширений по-умолчанию для функции spl_autoload.
Теперь будут искаться файлы с расширением .php. Если вы захотите указать больше расширений, то укажите их все через запятую.
С помощью spl_autoload_register вы можете зарегистрировать сразу несколько функций, все они будут помещены в стек. Какая была раньше зарегистрирована, та и будет первее.
Если вы хотите посмотреть все зарегистрированные функции, то вы можете воспользоваться функцией spl_autoload_functions, которая возвращает массив.
Если вы захотите удалить какую-нибудь из функций в стеке автозагрузки, то достаточно воспользоваться spl_autoload_unregister, передав название нужной функции.
Вот и все, что нужно знать об этой возможности. Используйте именно этот автозагрузчик, а не магический метод __autoload(), потому что spl_autoload более гибок и новее. Спасибо за внимание и удачного кодинга!
Копирование материалов разрешается только с указанием автора (Михаил Русаков) и индексируемой прямой ссылкой на сайт (http://myrusakov.ru)!
Добавляйтесь ко мне в друзья ВКонтакте: http://vk.com/myrusakov.
Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: http://vk.com/rusakovmy.
Если Вы не хотите пропустить новые материалы на сайте,
то Вы можете подписаться на обновления: Подписаться на обновления
Если у Вас остались какие-либо вопросы, либо у Вас есть желание высказаться по поводу этой статьи, то Вы можете оставить свой комментарий внизу страницы.
Порекомендуйте эту статью друзьям:
Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):
Комментарии ( 2 ):
Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.
Copyright © 2010-2021 Русаков Михаил Юрьевич. Все права защищены.
SPL Functions
Table of Contents
User Contributed Notes 8 notes
For some application I needed to reverse some standard iterators.
So I mocked up this flexible function.
Enjoy
/*
How to store SPL Iterator results (rather than just echo-and-forget):
I have to correct my implementation from before. The example before only supported correct read-access but failed on setting new values after creation of the ArrayMultiObject. Also i had to correct a bug that occured from my CopyPasteChange into the comment textarea.
This snippet now hopefully implements a fully functional multidimensional array, represented by an ArrayObject:
There is a RecursiveFilterIterator that makes the above code much easier. And then ther is ParentIterator thta is already a filtering recursive iterator that only accepts elements that have children, with a RecursiveDirectoryIterator as inner iterator you would obviously get only the directories. Further more it ensures that it creates the correct children. All in all you simply need to do this:
$it = new RecursiveDirectoryIterator($path);
$it = new ParentIterator($it);
$it = new RecursiveIteratorIteator($it);
recurse (new RecursiveDirectoryIterator ( ‘D:/’ ));
?>
Something to note that, at least to me, seems pretty important and is not entirely clear in the documentation is the fact that the ArrayObject class supports get/set on uni-dimensional keys and get ONLY on *passed* multi-dimensional keys/paths (see source below). If you, like me, need to support array accesss overloading for multi-dimensional data, you will need to derive from ArrayObject and overide the ArrayAccess interface methods to «walk» passed data and convert embedded arrays to objects of some kind.
Illustration of the issue:
$a = array(
«test» => array(
«one» => «dunno»,
«two» => array(
«peekabo» => «do you see me?»,
«anyone» => array(«there»)
)
)
);
$oArray = new ArrayObject($a);
var_dump($oArray);
$oArray[«three»] = «No problems here.»;
// NEITHER of the two below will work!
$oArray[«test»][«one»] = «Yes I do!»;
$oArray[«test»][«yes»] = array(
«hello» => «Goodbye!»
);
—
Note from the extension author:
Actually there is RecursiveArrayObject and RecursiveArrayIterator to deal with recursive structures. However this does not always solve all multidimensional issues as expected.
This code is an example. By using classes like this, you gives a chance to create classes which extends another class but have most of the ability what a class extends ArrayObject (like multiple inheritance):
function __toString ()
<
return ‘String test’ ;
> // function
> // class
/* Generated output:
1
foo
4
0=>1
1=>2
2=>3
3=>4
array
0 => int 1
1 => int 2
2 => int 3
3 => int 4
String test
*/
?>
For proper use you must be define all these methods except getArray()
Browse SPL’s sources to be a very helpful think.