浅析PHP类的主动加载和命名空间
浅析PHP类的主动加载和命名空间
php是使用require(require_once)和include(include_once)关键字加载类文件。但是在实际的开发工程中我们根本上不会去使用这些关键字去加载类。 由于这样做会使得代码的保护相当的艰难。实际的开发中我们会在文件的开端位置用use关键字使用类,然后直接new这个类就可以了. 至于类是如何加载的,一样都是框架或者composer去实现的。
<?php use Illuminate\Container\Container; $container = new Container();
主动加载
我们可以通过一段伪代码来模拟一下在类的实例化工程中类是怎样工作的
function instance($class) { // 假如类已加载则返回其实例 if (class_exists($class, false)) { return new $class(); } // 查看 autoload 函数可否被会员定义 if (function_exists('__autoload')) { __autoload($class); // 最后一次加载类的时机 } // 再次检查类可否存在 if (class_exists($class, false)) { return new $class(); } else { // 系统:我实在没辙了 throw new Exception('Class Not Found'); } }
php在说话层面供给了**__autoload** 魔术办法给会员来实现本人的主动加载逻辑。当会员去new一个类的时候,假如该类没有被加载,php会在抛出错误前调取**__autoload办法去加载类。下面的例子中的__autoload**办法只是简便的输出要加载类的名称, 并没有去实际的加载对应的类, 所以会抛出错误。
<?php use Illuminate\Container\Container; $container = new Container(); function __autoload($class) { /* 详细处置逻辑 */ echo $class;// 简便的输出要加载类的名称 } /** *
运转结果
Illuminate\Container\Container Fatal error: Uncaught Error: Class 'Illuminate\Container\Container' not found in D:\project\php\laravel_for_ci_cd\test\ClassLoader.php:5 Stack trace: #0 {main} thrown in D:\project\php\laravel_for_ci_cd\test\ClassLoader.php on line 5 */
清楚了 **__autoload** 函数的工作道理之后,我们来用它去实现一个最简便主动加载。我们会有index.php和Person.php两个文件在统一个名目下。
//index.php <?php function __autoload($class) { // 按照类名肯定文件名 $file = './'.$class . '.php'; if (file_exists($file)) { include $file; // 引入PHP文件 } } new Person(); /*---------------------分割线-------------------------------------*/ //Person.php class Person { // 对象实例化时输出当前类名 function __construct() { echo '<h1>' . __CLASS__ . '</h1>'; } } /**运转结果 * 输出 <h1>Person</h1> */
命名空间
命名空间并不是啥新颖的事务,许多说话都早就支撑了这个特性(只是叫法不雷同),它主要解决的一个问题就是命名冲突! 就仿佛日常生活中许多人都会重名,我们必需要通过一些标识来区分他们的不一样。比方说此刻我们要用php介绍一个叫张三的人 ,他在财务部门工作。我们可以这样描写。
namespace 财务部门; class 张三 { function __construct() { echo '财务部门的张三'; } }
这就是张三的根本材料 , namespace是他的部门标识,class是他的名称. 这样大家就可以知道他是财务部门的张三而不是工程部门的张三。
非限制名称,限制名称和完全限制名称
1.非限制名称,或不包括前缀的类名称,例如 $comment = new Comment(); 假如当前命名空间是Blog\Article,Comment将被解析为、\Blog\Article\Comment。假如使用Comment的代码不包括在任何命名空间中的代码(全局空间中),则Comment会被解析为\Comment。
留意: 假如文件的开头有使用use关键字 use one\two\Comment; 则Comment会被解析为 **one\two\Comment**。
2.限制名称,或包括前缀的名称,例如 $comment = new Article\Comment(); 假如当前的命名空间是Blog,则Comment会被解析为\Blog\Article\Comment。假如使用Comment的代码不包括在任何命名空间中的代码(全局空间中),则Comment会被解析为\Article\Comment。
3.完全限制名称,或包括了全局前缀操纵符的名称,例如 $comment = new \Article\Comment(); 在这种状况下,Comment总是被解析为\Article\Comment。
spl_autoload
接下来让我们要在含有命名空间的状况下去实现类的主动加载。我们使用 spl_autoload_register() 函数来实现,这需要你的 PHP 版本号大于 5.12。spl_autoload_register函数的功效就是把传入的函数(参数可认为回调函数或函数名称情势)注册到 SPL __autoload 函数队列中,并移除系统默许的 **__autoload()** 函数。一旦调取 spl_autoload_register() 函数,当调取不决义类时,系统就会按次序调取注册到 spl_autoload_register() 函数的所有函数,而**不是主动调取 __autoload()** 函数。
此刻, 我们来创立一个 Linux 类,它使用 os 作为它的命名空间(倡议文件名与类名保持一致):
<?php namespace os; // 命名空间 class Linux // 类名 { function __construct() { echo '<h1>' . __CLASS__ . '</h1>'; } }
接着,在统一个名目下创建一个 index.php文件,使用 spl_autoload_register 以函数回调的方式实现主动加载:
<?php spl_autoload_register(function ($class) { // class = os\Linux /* 限制类名途径映射 */ $class_map = array( // 限制类名 => 文件途径 'os\\Linux' => './Linux.php', ); /* 按照类名肯定文件途径 */ $file = $class_map[$class]; /* 引入相关文件 */ if (file_exists($file)) { include $file; } }); new \os\Linux();
这里我们使用了一个数组去留存类名与文件途径的关系,这样当类名传入时,主动加载器就知道该引入哪个文件去加载这个类了。但是一旦文件多起来的话,映射数组会变得很长,这样的话保护起来会相当费事。假如命名能遵照统一的约定,就可以让主动加载器主动解析推断类文件所在的途径。接下来要介绍的PSR-4 就是一种被广泛采纳的约定方式
PSR-4标准
PSR-4 是关于由文件途径主动载入对应类的相关标准,标准规定了一个完全限制类名需要具有以下构造:
<顶级命名空间>(<子命名空间>)*<类名>
PSR-4 标准中必需要有一个顶级命名空间,它的意义在于表示某一个非凡的名目(文件基名目)。子命名空间代表的是类文件相关于文件基名目的这一段途径(相对途径),类名则与文件名保持一致(留意大小写的不同)。
举个例子:在全限制类名 \app\view\news\Index 中,假如 app 代表 C:\Baidu,那么这个类的途径则是 C:\Baidu\view\news\Index.php.我们就以解析 \app\view\news\Index 为例,编写一个简便的 Demo:
<?php $class = 'app\view\news\Index'; /* 顶级命名空间途径映射 */ $vendor_map = array( 'app' => 'C:\Baidu', ); /* 解析类名为文件途径 */ $vendor = substr($class, 0, strpos($class, '\\')); // 取出顶级命名空间[app] $vendor_dir = $vendor_map[$vendor]; // 文件基名目[C:\Baidu] $rel_path = dirname(substr($class, strlen($vendor))); // 相对途径[/view/news] $file_name = basename($class) . '.php'; // 文件名[Index.php] /* 输出文件所在途径 */ echo $vendor_dir . $rel_path . DIRECTORY_SEPARATOR . $file_name;
更多PHP相关知识,请拜访PHP中文网!
以上就是浅析PHP类的主动加载和命名空间的具体内容,更多请关注百分百源码网其它相关文章!