php自动加载的深入理解

那时候我总是能起的那么早,看到鸟儿在舞蹈...

使用require_once

文件位于同级目录下
class.php

1
2
3
4
5
6
7
8
9
10
11
12
<?php

class Test
{
public $name = 'yangzie';

public function getName()
{
return $this->name;
}

}

index.php

1
2
3
4
5
6
7
<?php

require_once 'class.php';

$test = new Test();

echo $test->getName();

使用__autoload

Test.php

1
2
3
4
5
6
7
8
9
10
11
12
<?php

class Test
{
public $name = 'yangzie';

public function getName()
{
return $this->name;
}

}

index.php

1
2
3
4
5
6
7
8
9
<?php

function __autoload($class_name) {
require_once $class_name . '.php';
}
// 这里要求类名和文件名保持一致,注意大小写;
$test = new Test();

echo $test->getName();

使用spl_autoload_register

第一种方式

Test.php

1
2
3
4
5
6
7
8
9
10
11
12
<?php

class Test
{
public $name = 'yangzie';

public function getName()
{
return $this->name;
}

}

index.php

1
2
3
4
5
6
7
8
9
<?php

function my_autoload($class_name) {
require_once $class_name . '.php';
}
spl_autoload_register("my_autoload");
$test = new Test();

echo $test->getName();

第二种方式

Test.class.php

1
2
3
4
5
6
7
8
9
10
11
12
<?php

class Test
{
public $name = 'yangzie';

public function getName()
{
return $this->name;
}

}

index.php

1
2
3
4
5
6
7
8
<?php

spl_autoload_extensions('.class.php');// 寻找扩展名
// 如果我们类的后缀名既有.class.php 还有.php, 可以这样 spl_autoload_extensions('.class.php,.php');
set_include_path(get_include_path().PATH_SEPARATOR."");// 这里的"" 指的是类文件的目录,这里是平级目录
spl_autoload_register();

echo (new Test())->getName();

第三种方式

Test.class.php

1
2
3
4
5
6
7
8
9
10
11
12
<?php

class Test
{
public $name = 'yangzie';

public function getName()
{
return $this->name;
}

}

index.php

1
2
3
4
5
6
7
8
9
10
11
<?php

function my_autoload($class_name) {
spl_autoload_extensions('.class.php');
set_include_path(get_include_path().PATH_SEPARATOR."");
spl_autoload($class_name);
}

spl_autoload_register('my_autoload');

echo (new Test())->getName();

第四种方式

index.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php


class Index
{

public static function my_autoload($class_name) {
require_once $class_name . '.php';
}

public static function getLoader()
{
spl_autoload_register(['Index','my_autoload'], true, true);
}
}

Index::getLoader();
echo (new Test())->getName();

Test.php

1
2
3
4
5
6
7
8
9
10
11
12
<?php

class Test
{
public $name = 'yangzie';

public function getName()
{
return $this->name;
}

}

PSR

PSR是由PHP Framework Interoperability Group(PHP通用性框架小组)发布的一系列标准/规范,目前包括了PSR-0~PSR-4共4个,而PSR-0就是其中的自动加载标准(其后的PSR-4称为改进的自动加载的标准,是PSR-0的补充。PSR-0使用更广泛)
PSR-4风格:

1
2
3
4
-|vendor
--|package
---|src
----|demo.php

如在我们的laravel项目下建立一个与app文件夹同级的目录;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 新建目录accmd, 与app目录同级
acmd\test\yangze\Yang.php

// Yang.php文件内容

<?php
namespace Acmd\Test\Yangzie;

class Yang
{
public function demo()
{
echo 'demo';
}
}

尝试在调用这个类

1
2
3
$yang = new \Acmd\Test\Yangzie\Yang();
$yang->demo();
// error not found

使用composer自动加载

1
2
3
4
5
6
7
8
9
"autoload": {
"classmap": [
"database"
],
"psr-4": {
"App\\": "app/",
"Acmd\\":"acmd/"
}
},

执行命令: composer dump-autoload 即可

laravel下的自动加载

入口文件public/index.php

1
require __DIR__.'/../bootstrap/autoload.php';

bootstrap/autoload.php

1
require __DIR__.'/../vendor/autoload.php';

vendor/autoload.php

1
2
3
4
5
6
7
<?php

// autoload.php @generated by Composer

require_once __DIR__ . '/composer' . '/autoload_real.php';

return ComposerAutoloaderInit5205c428ce42c79967c9b7a7be4a7d82::getLoader();

这个文件包含了laravel对classmap,psr-0,psr-4,files的具体实现,主要只有这么一个方法 getLoader;

附录

composer 自动加载文件
文件位置: acmd和app同目录
acmd\test\commom.php
composer.json

1
2
3
4
5
6
7
8
9
10
"autoload": {
"classmap": [
"database"
],
"psr-4": {
"App\\": "app/",
"Acmd\\":"acmd/"
},
"files":["acmd/test/commom.php"]
},

执行命令: composer dump-autoload

我们自己的项目如何使用

在使用composer安装好相关的依赖包以后, 只要在我们的项目入口文件index.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
require_once 'vendor/autoload.php';

use Flc\Alidayu\Client;
use Flc\Alidayu\App;
use Flc\Alidayu\Requests\AlibabaAliqinFcSmsNumSend;

$config = [
'app_key' => '*****',
'app_secret' => '*****'
];

$client = new Client(new App($config));
$req = new AlibabaAliqinFcSmsNumSend;

$req->setRecNum('15829465509')
->setSmsParam([
'name' => '杨国奇',
'days' => rand(100000, 999999)
])
->setSmsFreeSignName('叶子坑')
->setSmsTemplateCode('SMS_87315128');

$resp = $client->execute($req);

// 返回结果
print_r($resp);

之后, 我们只要使用合适的命名空间就可以实现自动载入