Home > Article > Backend Development > What you don’t know about PHP – automatic loading
One of the earliest problems that many friends face when learning PHP is the love and death between require, include and require_once, include_once.
After understanding the story of their love and death, they often start to use the frame. The framework is certainly a good tool for work, but do you know what happens when you usually new a new class? Have you ever wondered why when we follow the specifications, everything will be automatically loaded for us? Let's explore and discover the mysteries.
Timeline
Steam Age
Do you often see code like this at the top of PHP code.
require 'lionis.php'; require 'is.php'; require 'cool.php';
If you just introduce a few PHP scripts, that's acceptable. When thousands of scripts are introduced, explosions are inevitable. If you change the name of a script, you also need to change the name of each script that introduces the changed script. Can it not explode? How can I go around typing this sentence?
Electrical Era
In the PHP electrical era, the __autoload and spl_autoload_register functions began to appear to register custom automatic loading strategies.
In layman’s terms, __autoload and spl_autoload_register are a killer organization, and they will hire killers (functions) from various countries. When we want to get rid of someone (new), we only need to provide the name (class name), and the rest "Killer" will help us get it done.
__autoload
PHP 5 starts to provide this function Portal. When the class you use cannot be found, it throws the class name into this function as a parameter.
<?php// Lionis.phpclass Lionis { public function __construct() { echo '欧耶耶, 我就是 Lionis'; } }
<?php // index.php function __autoload($classname) { $filename = './' . $classname . '.php'; require_once $filename; } $lionis = new Lionis();
Output
欧耶耶, 我就是 Lionis
spl_autoload_register
If our project is very large and old or you are a young pioneer who loves to toss, the things that need to be introduced have different specifications. At this time, if they are placed in the __autoload function, this function It will expand soon. Moreover, __autoload is globally unique and may cause errors if it is occupied by others. (To make a person perish, he must first swell it.)
PHP 5.1.2 starts to provide this function portal, registering the given function as the implementation of __autoload. Therefore, when we use some frameworks or plug-ins, function_exists(spl_autoload_register) may appear for compatibility.
<?php function lionisIsCoolFind($classname) { require './' . $classname . '.php'; } // 函数 spl_autoload_register('lionisIsCoolFind'); // 匿名函数 spl_autoload_register(function($require) { require './' . $classname . '.php'; }); // 类中的函数 spl_autoload_register(array('Lionis', 'loadClass'));
Oh yeah, now we can write many different autoloading functions.
Information Age
Master, be careful, there is a demon ahead! . If each of us implements our own set of autoloading methods, each PHP component and framework uses a unique autoloader, and each framework uses different logic to load PHP classes, interfaces, and traits.
Then when we use some third-party frameworks, we also need to figure out the autoloader in the boot file. That will take a lot of time. PHP-FIG recognizes this problem and recommends using the PSR-4 specification to promote interoperability between components so that we can use an autoloader.
PSR-4 规范
利用命名空间的前缀和文件系统中的目录对应起来。
映射关系为
namespace => filePath \Lionis\Cool => cool
带有命名空间的类
<?php // 该文件为 cool/Real.phpnamespace \ Lionis\Cool;class Real { }
创建一个对象
<?php// 该文件为 index.php$lionis = new \ Lionis\Cool\Real;
这个时候,按照 PSR-4 的规范,自动加载器应该去加载 cool/ 目录下的 Real.php。
不对!那这样不是还要自己去实现 自动加载器 嘛,不然怎么 无中生有 出现 自动加载器 呢?难道官方 内置 了?
你 out 了吧,我们可以使用依赖管理器 composer 来生成 PSR-4 自动加载器。你可能会疑问,那我的旧项目没有遵循 PSR-4 规范怎么办?嘿嘿,让我们来探索发现一下 composer 是怎么解决这个问题的吧。
Composer
哦吼吼,我们这次的重点在与探究自动加载,所以 composer 的安装和使用等,就不去讨论了。
composer 自动加载设置了 4种 加载方式:
PSR-0
PSR-4
classmap
files
PSR-0
要求命名空间和目录层层对应,且可以使用 _ 作为路径分隔符,但是这会导致目录结果变得过深。
在 composer 执行 install 等操作时,composer 会把文件中的配置存储在 vendor/composer/autoload_psr0.php文件中的返回数组中。
例如:定义了Very\Good=>vendor\Lionis\IsReal\Cool,在调用 use Very\Good\Love\SomeClass,PSR-0 加载的实际目录为 vendor/Lionis/IsReal/Cool/Very/Good/Love/SomeClass.php。
对吧,这简直深得吓人,所以 PSR-0 被官方废除了。但是一些主流的框架已经实现了 PSR-0,为了向下兼容还是要实现 PSR-0。
composer.json配置:
"autoload": { "psr-0": { "Very\\Good": "vendor\Lionis\IsReal\Cool" } }
PSR-4
PSR-4 是现在比较推荐的方法,用于替代 PSR-0。
与 PSR-0 不同的是,取消掉了 _ 作为分隔符和目录结构。
在 composer 执行 install 等操作时,composer 会把文件中的配置存储在 vendor/composer/autoload_psr4.php文件中的返回数组中。
例如:定义了Very\Good=>vendor\Lionis\IsReal\Cool,在调用 use Very\Good\
Love\SomeClass,PSR-4 加载的实际目录为 vendor/Lionis/IsReal/Cool/Love/SomeClass.php。
composer.json配置:
"autoload": { "psr-4": { "Very\\Good": "vendor\Lionis\IsReal\Cool" } }
classmap
classmap 通过配置指定的目录和文件,在 composer 执行 install 等操作时,composer 会去扫描对应的目录下以.php结尾的文件中的 class,并存储在 vendor/composer/autoload_classmap.php文件中的返回数组中。
composer.json配置:
"autoload": { "classmap": [ "Lionis/", "Xiaoer/" ] }
如果 Lionis 下有一个叫 VeryCool的文件,那么在vendor/composer/autoload_classmap.php 中会生成。
<?php // autoload_classmap.php @generated by Composer $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( 'VeryCool' => $baseDir . '/Lionis/VeryCool.php', // 其他的映射 );
files
files 就是直接简单粗暴的加载文件。在 composer 执行 install 等操作时,composer 会把文件中的配置存储在vendor/composer/autoload_static.php文件中的生成一个 $files 数组。
composer.json 配置:
"autoload": { "files": ["Lionis/Very/Cool.php"] }