重温PHP自动加载机制

PHP自动加载机制

    • 自动加载的两种方式
      • 1. ```__autoload```魔术方法
      • 2. ```spl_autoload_register```方法
        • ```spl_autoload_register```的使用方式

自动加载的两种方式

1. __autoload魔术方法

该方法使用PHP5和PHP7,并且在PHP7.2以后的版本已经被移除,因为该方法有一个致命缺陷,该方法不能重复定义,也就是说我们只能定义一种加载文件的模式,当我们应用其他插件扩展的时候就有问题。

示例如下:

  • 项目目录结构:
|-- autoload_project
	|-- test_a
		|-- TestB.php
	|-- index.php
	|-- TestA.php
	|-- TestC.php

#file path: /autoload_project/index.php
function __autoload($name) {
  var_dump($name);
  var_dump("-------");
  $filename = __DIR__ . '/'.$name.".php";
  if (file_exists($filename))
    require $filename;
}
$a = new TestA();
$a->printInfo();
echo "index";


#file path: /autoload_project/TestA.php
class TestA {
  function __autoload($name) {
    var_dump($name);
    var_dump("+++++++++++++++");
    $filename = __DIR__ . '/testA/'.$name.".php";
    if (file_exists($filename))
      require $filename;
  }

  function printInfo() {
    $b = new TestB();
    $b->printInfo();

    echo "testA";
  }
}

#file path: /autoload_project/test_a/TestB.php
class TestB {
  function __autoload($name) {
    var_dump($name);
    var_dump("+++++++++++++++");
    $filename = __DIR__ . '/../'.$name.".php";
    if (file_exists($filename))
      require $filename;
  }

  function printInfo() {
    $b = new TestC();
    $b->printInfo();
    echo "testA child testB";
  }
}

#file path: /autoload_project/TestC.php
class TestC {
  function printInfo() {
    echo "testC";
  }
}

执行结果如下:

string(5) "TestA" string(7) "-------" string(5) "TestB" string(7) "-------"
Fatal error: Class 'TestB' not found in D:\WWW\autoload\TestA.php on line 23

可以看到index中找TestA类时,执行了index中的__autoload方法,这一步没问题,但是TestA类执行printInfo方法的时候,加载TestB类的时候,应该要使用TestA类的__autoload方法,但是实际情况是执行了index中的__autoload方法

为了解决这种问题,引入了第二种自动加载的方法

2. spl_autoload_register方法

spl_autoload_register方法就是解决了__autoload只能定义一次的问题。它实际上创建了 autoload 函数的队列,按定义时的顺序逐个执行。

上面例子的代码可以修改为如下:


#file path: /autoload_project/index.php

function loadfuncIndex($name) {
    $filename = __DIR__ . '/'.$name.".php";
    if (file_exists($filename))
      require $filename;
  }

spl_autoload_register("loadfuncIndex");

$a = new TestA();
$a->printInfo();
echo "index";

#file path: /autoload_project/TestA.php
class TestA {
  public static function loadfuncA($name) {
    $filename = __DIR__ . '/testA/'.$name.".php";
    if (file_exists($filename))
      require $filename;
  }


  function printInfo() {

    spl_autoload_register("TestA::loadfuncA");

    $b = new TestB();
    $b->printInfo();

    echo "testA";
  }
}

#file path: /autoload_project/test_a/TestB.php

class TestB {
  public function loadfuncB($name) {
    $filename = __DIR__ . '/../'.$name.".php";

    if (file_exists($filename))
      require $filename;
  }



  function printInfo() {

    spl_autoload_register(array($this, "loadfuncB"));

    $b = new TestC();
    $b->printInfo();
    echo "testA child testB";
  }
}

输出结果如下:

testCtestA child testBtestAindex

spl_autoload_register的使用方式

spl_autoload_register(funName); // 直接注册一个普通加载函数
spl_autoload_register(obj::method); // 注册一个静态加载方法
spl_autoload_regitser(array(obj, method));
spl_autoload_regitser(function($name){ }); //匿名函数

现在最常见的自动导入是结合命名空间来使用,命名空间相关请参见回顾明明空间

你可能感兴趣的:(PHP,php,自动导入)