php自动加载

php的自动加载

自动加载原理

咱们使用另外一个文件定义的一个class的时候,传统的状况下须要require XXX.phpphp

//Good.php
<?php
  class Good{
    //......
  }
 
//use.php
<?php
  require 'Good.php';   //包含进来文件    
  $good = new Good();   //如今可使用Good类

可是写require真的很烦!!如今可使用一个自动加载函数,发现类没有被定义的时候自动根据咱们定义的规则帮咱们去require须要的文件。git

//Good.php
<?php
  class Good{
    //......
  }

//use.php
<?php
function __autoload($className){
  require $className . '.php';  //定义包含的规则
}

$good = new Good(); //可使用Good类,发现没有定义,会自动调用__autoload函数,如今'Good'做为参数传入了__autoload函数,去包含须要的文件

spl_autoload_register

__autoload函数不能解决全部的问题,如今的项目已经很是复杂,光一个autoload函数已经不能知足须要了,由于可能不一样的模块使用了不一样的自动加载规则。github

spl_autoload_register将函数注册到SPL autoload函数队列中,它实际上建立了 __autoload 函数的队列,按定义时的顺序逐个执行。相比之下,__ autoload() 只能够定义一次。web

函数原型

bool spl_autoload_register ([ callable $autoload_function [, bool $throw = true [, bool $prepend = false ]]] )
  • autoload_functionsql

    欲注册的自动装载函数。若是没有提供任何参数,则自动注册 autoload 的默认实现函数spl_autoload()。app

  • throw函数

    此参数设置了 autoload_function 没法成功注册时, spl_autoload_register()是否抛出异常。ui

  • prependthis

    若是是 true,spl_autoload_register() 会添加函数到队列之首,而不是队列尾部。spa

函数使用

sql_autoload_resister('load_function'); //函数名
sql_autoload_resister(array('load_object', 'load_function')); //类和静态方法
sql_autoload_resister('load_object::load_function'); //类和方法的静态调用

//php 5.3以后,也能够像这样支持匿名函数了。
spl_autoload_register(function($className){
    if (is_file('./lib/' . $className . '.php')) {
        require './lib/' . $className . '.php';
    }
});

note:使用了spl_autoload_register以后原来的__autoload函数就失效了,若是须要继续使用,须要显示的注册它

if (function_exists('__autoload')) {
   spl_autoload_register('__autoload');
 }

//。。。。。。

 spl_autoload_register('your_autoload_function');   //如今注册另外一个

是否继续在自动加载函数队列中查找不取决于加载函数的返回值和是否require了文件,只有真正require须要的文件才会中止

//Good.php位于app文件夹下
<?php
  class Good{
    //......
  }


//Another.php,位于use同级文件夹下
<?php
class Another{
}


//use.php
<?php
function load1($className)
{
    echo "load1\n";
    if (file_exists($className.'.php')) {
        echo 'found: '.$className.PHP_EOL;
        require $className;
    } else {
        echo 'not found: '.$className.PHP_EOL;
    }
}

function load2($className)
{
    echo "load2\n";
    require 'Another.php';
    echo 'require another class'.PHP_EOL;
    return true;
}

function load3($className)
{
    echo "load3\n";
    if (file_exists('app/'.$className.'.php')) {
        echo 'found '.$className.PHP_EOL;
        require 'app/'.$className.'.php';
    } else {
        echo 'not found: '.$className.PHP_EOL;
    }
}


spl_autoload_register('load1');
spl_autoload_register('load2');
spl_autoload_register('load3');

$a = new Good();

输出以下

load1
not found: Good
load2
require another class
load3
found Good

可使用spl_autoload_functions()得到注册的全部函数

Array
(
    [0] => load1
    [1] => load2
    [2] => load3
)

取消注册的自动加载函数spl_autoload_unregister

spl_autoload_unregister('load1');

spl_autoload()是__autoload()函数的默认实现

提供了autoload()的一个默认实现。若是不使用任何参数调用 spl_autoload_register() 函数,则之后在进行 autoload() 调用时会自动使用此函数。

自动加载和命名空间

PSR-4自动加载规范

完整的规范请参考PSR-4: Autoloader

标准的类名应该具备下列形式

\<NamespaceName>(\<SubNamespaceNames>)*\<ClassName>

须要强调的:

  • 完整的类名中任意一部分中的下滑线都是没有特殊含义的
  • 全部类名都必须是大小写敏感的
  • 全部类名都必须是大小写敏感的

当根据命名空间载入文件时候:

  • 完整的类名中,去掉最前面的命名空间分隔符,前面连续的一个或多个命名空间和子命名空间,做为“命名空间前缀”,其必须与至少一个“文件基目录”相对应。
  • 紧接命名空间前缀后的子命名空间必须与相应的”文件基目录“相匹配,其中的命名空间分隔符将做为目录分隔符。
  • 末尾的类名必须与对应的以 .php 为后缀的文件同名。
  • 自动加载器(autoloader)的实现必定不能抛出异常、必定不能触发任一级别的错误信息以及不该该有返回值。

例子

完整类名 命名空间前缀 文件基目录 文件路径
\Acme\Log\Writer\File_Writer Acme\Log\Writer ./acme-log-writer/lib/ ./acme-log-writer/lib/File_Writer.php
\Aura\Web\Response\Status Aura\Web /path/to/aura-web/src/ /path/to/aura-web/src/Response/Status.php
\Symfony\Core\Request Symfony\Core ./vendor/Symfony/Core/ ./vendor/Symfony/Core/Request.php
\Zend\Acl Zend /usr/includes/Zend/ /usr/includes/Zend/Acl.php

实现示例

采用了匿名函数的方式

<?php
/**
 * An example of a project-specific implementation.
 *
 * After registering this autoload function with SPL, the following line
 * would cause the function to attempt to load the \Foo\Bar\Baz\Qux class
 * from /path/to/project/src/Baz/Qux.php:
 *
 *      new \Foo\Bar\Baz\Qux;
 *
 * @param string $class The fully-qualified class name.
 * @return void
 */
spl_autoload_register(function ($class) {
    // project-specific namespace prefix
    $prefix = 'Foo\\Bar\\';

    // base directory for the namespace prefix
    $base_dir = __DIR__ . '/src/';

    // does the class use the namespace prefix?
    $len = strlen($prefix);
    if (strncmp($prefix, $class, $len) !== 0) {
        // no, move to the next registered autoloader
        return;
    }

    // get the relative class name
    $relative_class = substr($class, $len);

    // replace the namespace prefix with the base directory, replace namespace
    // separators with directory separators in the relative class name, append
    // with .php
    //下边这一行很关键
    $file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';

    // if the file exists, require it
    if (file_exists($file)) {
        require $file;
    }

});

参考资料:

相关文章
相关标签/搜索