自动加载

PhalApi 2.x 的自动加载很简单,完全遵循于PSR-4规范,并且兼容 PhalApi 1.x 版本的加载方式。

在PhalApi 2.x这里,我们主要介绍PSR-4的使用,如果你已经熟悉此约定成俗的命名规范,可跳过这一节。

PSR-4规范一瞥

简单来说,类的全称格式如下:

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

其中,<NamespaceName>为顶级命名空间;<SubNamespaceNames>为子命名空间,可以有多层;<ClassName>为类名。

PhalApi 2.x 的命名规范

PhalApi 2.x 的项目的顶级命名空间,默认是app

Api层命名规范

默认情况下,假设有一个为?s=User.Login的用户登录接口服务,则它对应的Api层接口类文件为:

  1. /path/to/phalapi/src/app/Api/User.php

类名则为app\Api\User,即顶级命名为app,子命名空间为Api,类名为User。由于存在命名空间,所以其代码实现片段如下:

  1. <?php
  2. namespace App\Api;
  3. use PhalApi\Api;
  4. class User extends Api {
  5. public function Login() {
  6. // TODO
  7. }
  8. }

多层子命名空间

当存在多层子命名空间时,则需要多层子目录;反之亦然,即如果存在多个子目录,则需要多层子命名空间。例如,对于接口服务?s=Weixin_User.Login,其文件路径为:

  1. /path/to/phalapi/src/app/Api/Weixin/User.php

实现代码片段为:

  1. <?php
  2. namespace App\Api\Weixin;
  3. use PhalApi\Api;
  4. class User extends Api {
  5. public function Login() {
  6. // TODO
  7. }
  8. }

需要注意的是,此时当前的命名空间为App\Api\Weixin,而不再是App\Api

Domain层和Model层的命名规范

Domain层,和Model层的命名规范,和Api层的一样,或者说其他层级或者目录的规范也是如此,可依次类推。

例如,对于类app\Domain\User,其文件路径为:

  1. /path/to/phalapi/src/app/Domain/User.php

实现代码片段为:

  1. <?php
  2. namespace App\Domain;
  3. class User { }

而对于类app\Domain\Weixin\User,其文件路径为:

  1. /path/to/phalapi/src/app/Domain/Weixin/User.php

实现代码片段为:

  1. <?php
  2. namespace App\Domain\Weixin;
  3. class User { }

如何实例化

实例化的方式有两种,对应命名空间两种不同的使用方式。

先use,再实例

通常情况下,都是先use,然后再实例化。例如,在Api层需要用到Domain层的类时,可以这样:

  1. <?php
  2. namespace App\Api;
  3. use PhalApi\Api;
  4. use App\Domain\User as DomainUser; // 在这里先use
  5. class User extends Api {
  6. public function Login() {
  7. $domainUser = new DomainUser();
  8. }
  9. }

因为存在两个User类,所以在use领域类时需要改用别名DomainUser。如果当前命名空间和待使用的类是同一命名空间,则可以省略use。例如在App\Domain\User类中使用App\Domain\Friends

  1. <?php
  2. namespace App\Domain;
  3. class User {
  4. public function Login() {
  5. $friend = new Friend(); // 可直接使用Friend类
  6. }
  7. }

使用完整类名实例化

另一种情况下,可不用先use,直接使用带命名空间前缀的完整类名来实例化。例如,上面的可改成:

  1. <?php
  2. namespace App\Api;
  3. use PhalApi\Api;
  4. class User extends Api {
  5. public function Login() {
  6. $domainUser = new \App\Domain\User();
  7. }
  8. }

值得注意的是,在当前命名空间下,如果需要引用其他类,应该在最前面加上反斜杠,表示绝对路径,否则会导致类名错误,从而加载失败。即:

当前命名空间 类名 最终解析类名 区别
App\Api \App\Domain\User \App\Domain\User 最前面有反斜杠,正确
App\Api App\Domain\User App\Api\App\Domain\User 最前面缺少反斜杠,错误
App\Api \Exception Exception 最前面有反斜杠,使用PHP官方的异常类,正确
App\Api Exception App\ApiException 最前面缺少反斜杠,使用当前命名空间的异常类

如果当前没有命名空间,则最前面可不用加上反斜杠。

如何增加一个顶级命名空间?

在composer下,增加一个顶级命名空间很简单。首先,需要在根目录下的composer.json文件中追加psr-4配置,如在原有基础上添加一个Foo命名空间,则:

  1. {
  2. "autoload": {
  3. "psr-4": {
  4. "App\\": "src/app",
  5. "Foo\\": "src/foo"
  6. }
  7. }
  8. }

配置好后,执行composer更新操作:

  1. $ composer update

此时,对于顶级命名空间Foo,其源代码保存在/path/to/phalapi/src/foo下。其他类似,这里不再赘述。

需要注意的是,源代码目录需要自己手动添加,即分别添加以下几个常见目录:Api、Domain、Model、Common。以这里的Foo命名空间为例,需要丢创建以下目录:

  • src/foo/Api
  • src/foo/Domain
  • src/foo/Model
  • src/foo/Common
    接下来就可以正常开始开发了。在src/foo/Api目录下新增的接口服务,会同步实时显示在在线接口文档上。如这里添加src/foo/Api/Hello.php文件,并放置以下代码:
  1. // 文件 ./src/foo/Api/Hello.php
  2. <?php
  3. namespace Foo\Api;
  4. use PhalApi\Api;
  5. /**
  6. * Foo下的示例
  7. */
  8. class Hello extends Api {
  9. public function world() {
  10. return array('title' => 'Hello World in Foo!');
  11. }
  12. }

就可以看到:1.9 自动加载 - 图1

注意事项

对于初次使用composer和初次接触PSR-4的同学,以下事项需要特别注意,否则容易导致误解、误用、误导。

  • 1、在当前命名空间使用其他命名空间的类时,应先use再使用,或者使用完整的、最前面带反斜杠的类名。
  • 2、在定义类时,当前命名空间应置于第一行,且当存在多级命名空间时,应填写完整。
  • 3、命名空间和类,应该与文件路径保持一致,并区别大小写。
    例如:
  1. <?php
  2. namespace App\Api;
  3. use PhalApi\Api;
  4. class Site extends Api {
  5. public function test() {
  6. // 错误!会提示 App\Api\DI()函数不存在!
  7. DI()->logger->debug('测试函数调用');
  8. // 正确!调用PhalApi官方函数要用绝对命名空间路径
  9. \PhalApi\DI()->logger->debug('测试函数调用');
  10. }
  11. public function testMyFun() {
  12. // 错误!会提示 App\Api\my_fun()函数不存在!
  13. //(假设在./src/app/functions.php有此函数)
  14. my_fun();
  15. // 正确!调用前要加上用绝对命名空间路径
  16. \App\my_fun();
  17. }
  18. }

原文: http://docs.phalapi.net/#/v2.0/autoload