Home > Article > Backend Development > laravel - php 的 namespace 和 autoload 的问题
假设我的项目其中的一个目录:
<code>app == site ==== controller ====== IndexController.php ====== AccessController.php == api ==== controller ====== PostController.php </code>
假设 IndexController.php 的内容:
<code>namespace app\site\controller; class IndexController { // some code } </code>
项目是单入口,包含了 function autoload($className),我的问题:
假设项目约定了 namespace 中的名称必须和文件夹名称一致,并且类名称也和类文件同名(不包含下划线等奇怪的字符),那这样的话,$className 其实只需要把右斜杠换成 DIRECTORY_SEPARATOR 就可以找到对应的类文件了,比如:
<code>$obj = new \app\site\controller\IndexController(); </code>
或者
<code>class TestClass extends \app\site\controller\IndexController {} </code>
那 autoload 实际找到的就是 /app/site/controller/IndexController.php。
既然这样,那为什么 thinkphp 里面的 Think 类还要 $_map 呢?类似的还有 laravel 里的:
<code>autoload_namespaces.php autoload_classmap.php autoload_psr4.php </code>
比如这个是 autoload_psr4.php 里的内容:
<code>$vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( 'yii\\swiftmailer\\' => array($vendorDir . '/yiisoft/yii2-swiftmailer'), 'yii\\gii\\' => array($vendorDir . '/yiisoft/yii2-gii'), 'yii\\faker\\' => array($vendorDir . '/yiisoft/yii2-faker'), 'yii\\debug\\' => array($vendorDir . '/yiisoft/yii2-debug'), 'yii\\composer\\' => array($vendorDir . '/yiisoft/yii2-composer'), 'yii\\codeception\\' => array($vendorDir . '/yiisoft/yii2-codeception'), 'yii\\bootstrap\\' => array($vendorDir . '/yiisoft/yii2-bootstrap'), 'yii\\' => array($vendorDir . '/yiisoft/yii2'), 'cebe\\markdown\\' => array($vendorDir . '/cebe/markdown'), 'Faker\\' => array($vendorDir . '/fzaninotto/faker/src/Faker'), ); </code>
这里面通过数组定义的映射有什么作用啊?
假设我的项目其中的一个目录:
<code>app == site ==== controller ====== IndexController.php ====== AccessController.php == api ==== controller ====== PostController.php </code>
假设 IndexController.php 的内容:
<code>namespace app\site\controller; class IndexController { // some code } </code>
项目是单入口,包含了 function autoload($className),我的问题:
假设项目约定了 namespace 中的名称必须和文件夹名称一致,并且类名称也和类文件同名(不包含下划线等奇怪的字符),那这样的话,$className 其实只需要把右斜杠换成 DIRECTORY_SEPARATOR 就可以找到对应的类文件了,比如:
<code>$obj = new \app\site\controller\IndexController(); </code>
或者
<code>class TestClass extends \app\site\controller\IndexController {} </code>
那 autoload 实际找到的就是 /app/site/controller/IndexController.php。
既然这样,那为什么 thinkphp 里面的 Think 类还要 $_map 呢?类似的还有 laravel 里的:
<code>autoload_namespaces.php autoload_classmap.php autoload_psr4.php </code>
比如这个是 autoload_psr4.php 里的内容:
<code>$vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( 'yii\\swiftmailer\\' => array($vendorDir . '/yiisoft/yii2-swiftmailer'), 'yii\\gii\\' => array($vendorDir . '/yiisoft/yii2-gii'), 'yii\\faker\\' => array($vendorDir . '/yiisoft/yii2-faker'), 'yii\\debug\\' => array($vendorDir . '/yiisoft/yii2-debug'), 'yii\\composer\\' => array($vendorDir . '/yiisoft/yii2-composer'), 'yii\\codeception\\' => array($vendorDir . '/yiisoft/yii2-codeception'), 'yii\\bootstrap\\' => array($vendorDir . '/yiisoft/yii2-bootstrap'), 'yii\\' => array($vendorDir . '/yiisoft/yii2'), 'cebe\\markdown\\' => array($vendorDir . '/cebe/markdown'), 'Faker\\' => array($vendorDir . '/fzaninotto/faker/src/Faker'), ); </code>
这里面通过数组定义的映射有什么作用啊?
composer里的自动加载可以支持四种规范,psr-0(autoload_namespaces.php),psr-4,class-map,还有files,你如果自己写代码,这样约定好了,命名空间和路径保持一致,然后autoload加载按路径加载,当然不需要classmaps,但是很多类库是其他人写的,每个人习惯不一样,有的人喜欢psr-4,有的人喜欢psr-0,(大家规范都一样,声明的命名空间和路径不一样)时,就需要你说的 Classmap了,你可以看下composer的loader类
laravel里面的autoload_psr4.php是composer根据各个包的composer.json自动生成的,你研究一下composer就明白了
自动加载不止是你看到的能直接
<code>$obj = new \app\site\controller\IndexController();</code>
这些都已经是自动加载后的结果了。
如果没有自动加载,你这样子根本不能实现对象。
你脱离框架再这么写看看?
composer的自动加载是根据psr规则来的。
举个小例子:
如果你要实现一个工厂类,自动加载该如何实现?
题主可以试一下,就知道框架为什么要这么做了。
Composer的自动加载还可以自定义映射的,不一定是按平常的目录自动加载,可以看下Composer的文档,架构那一章,有说明每一个key的含义。