Slim研读笔记三之Composer(上)

来源:互联网 发布:gbgb55域名永久获取 编辑:程序博客网 时间:2024/06/04 19:38
上章节,我们自制了一款属于我们自己的Slim框架样板项目。这章节,我们从网络请求开始的地方index.php来研读slim框架。
<?phpuse Psr\Http\Message\ServerRequestInterface as Request;use Psr\Http\Message\ResponseInterface as Response;require '../vendor/autoload.php';// 数据库配置$config = require '../config/databases.php';// 声明一个应用主体对象并加载配置文件$app = new \Slim\App($config);// 依赖注入容器$container = $app->getContainer();// 在容器中注册Monolog日志组件$container['logger'] = function($c) {    $logger = new \Monolog\Logger('my_logger');    $file_handler = new \Monolog\Handler\StreamHandler('../logs/app.log');    $logger->pushHandler($file_handler);    return $logger;};// 在容器中注册Illuquent数据库Orm组件$container['db'] = function ($c) {    $capsule = new \Illuminate\Database\Capsule\Manager;    $capsule->addConnection($c['settings']['db']);    $capsule->setAsGlobal();    $capsule->bootEloquent();    return $capsule;};// 在容器中注册Twig模板引擎组件$container['view'] = function ($c) {    $view = new \Slim\Views\Twig('../templates', [        'cache' => '../storage/cache'    ]);    // 实例化并添加Slim特定的扩展    $basePath = rtrim(str_ireplace('index.php', '', $c['request']->getUri()->getBasePath()), '/');    $view->addExtension(new \Slim\Views\TwigExtension($c['router'], $basePath));    return $view;};// 在路由中渲染Twig模板$app->get('/hello/{name}', function (Request $request, Response $response, $args) {    //$name = $request->getAttribute('name');    //$response->getBody()->write("hello, $name");    //return $response;    return $this->view->render($response, 'index.htm', [        'name' => $args['name']    ]);})->setName('myname');$app->get('/', function(){    // 日志功能测试    $this->logger->addInfo("发生了一件有趣的事,并把它记录了下来");    // 数据库ORM对象测试    $users = $this->db->table('users')->get();    return "hello world";});$app->run();
这是index.php的全部内容。我们会顺序对其进行分析,首先是
use Psr\Http\Message\ServerRequestInterface as Request;use Psr\Http\Message\ResponseInterface as Response;
Psr\Http\Message是和PSR-7 HTTP消息接口相关的组件我们要使用它,必须先了解PSR-7接口规范。

PSR-7 HTTP消息接口

在PSR系列规范之前,PHP大牛们各自为战,代码命名千奇百怪,自动加载方式随心所欲。各项目的规范状态令人堪忧。后来PHPFIG为了实现组件间的互操作性,并为实现最佳编程和测试实践而制定了PSR规范。PSR并非官方规范,但其包含了众多知名开源项目参与并制定使其成为PHP项目的最佳规范。PSR-7 HTTP消息接口是已实施的PSR规范之一。HTTP消息是web开发的基础,Web浏览器和HTTP客户端创建发送到Web服务器的HTTP请求消息,然后由服务端返回HTTP响应消息。
每个HTTP请求消息都有特定的格式。
POST /path HTTP/1.1Host: example.comfoo=bar&baz=bat
请求的第一行是“请求行”,包含了HTTP请求方法,请求目标地址(通常为一个绝对URL或Web服务器路径),HTTP协议版本号。接下来是一个或多个HTTP头,一个空行和消息内容。
HTTP响应也具有相似的结构。
HTTP/1.1 200 OKContent-Type: text/plainThis is the response body
第一行是“状态行”,一次包含HTTP协议版本号,HTTP状态码以及对状态码进行描述的“原因短语”。接下来是一个或多个HTTP头,一个空行和一行消息内容。
PSR-7规范就是对HTTP消息与构成他们元素的抽象,该规范制定了抽象HTTP消息的接口。这里先进行PSR规范及PSR7消息接口的简单介绍,后面在看到源码的具体使用时再对其进行深入探讨。

Composer

代码中我们引入了Composer,Compser是管理依赖关系的工具。它允许你申明项目所依赖的代码库,它会在你的项目中为你安装他们。
Composer准备了一个自动加载文件,它可以加载Composer下载的库中的所有的类文件,使用它,你仅需这一行代码就足够:
require '../vendor/autoload.php’;

进入../vendor/autoload.php,看到如下代码
<?php// autoload.php @generated by Composerrequire_once __DIR__ . '/composer/autoload_real.php';return ComposerAutoloaderInit2b0e34f11c87555a88f83f6bf964b679::getLoader();

这行代码是Composer自动生成的,具体的生成方式我们暂时不必知道。第一行是引入了composer/autoload_real.php,第二行是调用autoload_real.php中的ComposerAutoloaderInitXxxx类的getLoader()方法。进入该类继续深剖…
class ComposerAutoloaderInit2b0e34f11c87555a88f83f6bf964b679{       private static $loader;    public static function loadClassLoader($class)    {                // 引入ClassLoader.php                if ('Composer\Autoload\ClassLoader' === $class) {                        require __DIR__ . '/ClassLoader.php’;                }        }    public static function getLoader()    {                // 典型的单例模式                if (null !== self::$loader) {                        return self::$loader;                }        // 注册一个自动加载函数到autoload队列中,由于第三个参数prepend为true,则队列会预先加载自动加载器loadClassLoader。        // 这意味着spl队列会首先使用loadClassLoader对应的自动加载器                spl_autoload_register(array('ComposerAutoloaderInit2b0e34f11c87555a88f83f6bf964b679', 'loadClassLoader'), true, true);        // 上面刚刚声明这里就已经用到啦,使用当前类的loadClassLoader方法,同时将返回值赋给静态变量$loader                self::$loader = $loader = new \Composer\Autoload\ClassLoader();                        // 将刚刚注册到autoload队列的loaderClassLoader自动加载器舍弃掉(反正已获取到Composer的加载类对象到self::$loader,这个加载器也就用不到了)         spl_autoload_unregister(array('ComposerAutoloaderInit2b0e34f11c87555a88f83f6bf964b679', 'loadClassLoader'));        。。。
问题变得愈发地清晰了,现在关键是要了解$loader的值——ClassLoader的类对象具体包含了哪些可用的方法?
通过注释我们了解到ClassLoader实现了PSR-0,PSR-4和类映射classmap的自动加载器。该自动加载器是如何实现的呢?如示例:
$loader = new \Composer\Autoload\ClassLoader();    // register classes with namespaces     $loader->add('Symfony\Component', __DIR__.'/component');     $loader->add('Symfony', __DIR__.'/framework');     // activate the autoloader     $loader->register();     // to enable searching the include path (eg. for PEAR packages)     $loader->setUseIncludePath(true);
在这个例子中,如果你尝试使用使用一个类在Symfony\Component命名空间或它的子命名空间(如Symfony\Component\Console)。自动加载器将会在component/*目录寻找类,如果没有寻找到该类它会回退到framework/目录。既然提到PSR4规范,那么我们更为详细的介绍PSR4.

PSR-4自动加载规范

PSR-0和PSR-4均是自动加载规范,目前PSR-0已被废弃。

一个完整的类名需要具备\<命名空间名>(\<子命名空间名>)*\<类名>这种格式。
  1. 完全限定类名必须有一个顶级命名空间(Vendor Name);
  2. 完全限定类名可以有多个子命名空间;
  3. 完全限定类名应该有一个终止类名;
  4. 下划线在完全限定类名中是没有特殊含义的;
  5. 字母在完全限定类名中可以是任何大小写的组合;
  6. 所有类名必须以大小写敏感的方式引用;
当从完全限定类名载入文件
  1. 在完全限定类名中,连续的一个或几个子命名空间构成的命名空间前缀(不包括顶级命名空间的分隔符),至少对应着至少一个基础目录。
  2. 在「命名空间前缀」后的连续子命名空间名称对应一个「基础目录」下的子目录,其中的命名空间分隔符表示目录分隔符。子目录名称必须和子命名空间名大小写匹配;
  3. 终止类名对应一个以 .php 结尾的文件。文件名必须和终止类名大小写匹配;
  4. 自动载入器的实现不可抛出任何异常,不可引发任何等级的错误;也不应返回值;
在Composer使用PSR-4风格
vendor/
    vendor_name/
        package_name/
            src/
                ClassName.php       # Vendor_Name\Package_Name\ClassName
            tests/
                ClassNameTest.php   # Vendor_Name\Package_Name\ClassNameTest

好了,今天关于Composer的学习就到此为止吧,我们今天介绍了Composer的引入,PSR7 HTTP消息接口、PSR-4自动加载规范,下节中我们会继续深入到Composer的ClassLoader类去学习Composer是如何实现类的自动加载的。











阅读全文
1 0