重温PHP自动加载机制

1. __autoload魔术方法

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

示例如下:

  • 项目目录结构:
|-- autoload_project
	|-- test_a
		|-- TestB.php
	|-- index.php
	|-- TestA.php
	|-- TestC.php
<?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";

<?php
#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";
  }
}
<?php
#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";
  }
}
<?php
#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 函数的队列,按定义时的顺序逐个执行。

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

<?php
#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";
<?php
#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";
  }
}
<?php
#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){ }); //匿名函数

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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值