TOP

一次框架性能的比较,引起了我对搭建web框架的兴趣(一)
2019-12-18 11:19:20 】 浏览:270
Tags:一次 框架 性能 比较 引起 搭建 web 兴趣

背景


一次无意的访问,点击到了一个专门做PHP性能测试的网站,看这里PHP Benchmarks

在里面发现了框架性能测试的结果,发现Laravel的框架性能尽然是最低的。瞬间受到了一万点的暴击,谁让最近一直用Laravel开发项目的呢。

说到底还是Laravel好用呀,方便不说,各方面支持的也不错,业务方面做的也是内部系统,哪怕性能慢点,也可以用前后端分离、负载均衡等手段解决掉,大体上也是够用。

不过,作为一个开发人员,理想还是要有的,这时就在想能不能采取Laravel框架的优点,用到什么就装什么,去掉一些请求到响应之间用不到的组件,精简框架。

之前也熟读过Laravel的源码,知道它的底层用的是Symfony的组件,毕竟没必要重复的造轮子。那么我们的框架之旅也将基于Symfony组件。。。

目录


一、Composer运行机制

二、框架前期准备

三、HttpFoundation组件封装Request、Response

四、路由处理

五、控制器处理相应功能(C)

六、分离模板(V)

七、分离模型(M)

八、剥离核心代码

九、优化框架

十、依赖注入(Dependency Injection)

正文


一、Composer运行机制

Composer的使用最关键的得益于PHP标准规范的出现,特别是其中的psr4,自动加载规范,规范了如何指定文件路径从而自动加载类定义,以及自动加载文件的位置。

既然讲到php文件的加载,我们就要聊一聊PHP的加载机制了。

在早前时,加载文件用的都是include、require,但这种加载有很大的局限性,相信同学们都知道,无论用到用不到都要加载大量的文件,相当繁琐。

于是就出现了autoload加载机制,它可以实现懒加载。

function __autoload($class)
{
    require_once ($class.".php");
}

当程序引用了未加载的类,就会自动调用__autoload方法,只要维护了__autoload方法,就可以懒加载文件。

但这里有一个很大的问题,就是程序中只能定义一次__autoload,这就需要花大尽力在__autoload中维护文件和空间的对应关系,特别是在大型项目,多人合作中更是繁琐。

而解决这个问题就是SPL Autoload

SPL Autoload:__autoload调用堆栈。

怎么理解这个堆栈呢,举个例子。

现有的框架比如ThinkPHP、Laravel等都有一个vendor目录,用于存放第三方库,现在vendor下有两个库。

monolog 处理系统日志
guzzlehttp 处理HTTP

当程序引用这两个库的命名空间,并调用monolog、guzzlehttp下面的类时,发现调用的类文件都能被找到。

这主要原理是monolog、guzzlehttp都自定义了类似autoload的方法,然后用spl_autoload_register将方法注册到了SPL堆栈中

这样的话,当程序调用类的时候,就会统一到SPL堆栈中寻找注册到堆栈中的autoload方法,并加载相应的文件。

以上就是php加载文件的方式,下面就用实战谈一谈composer的运行机制。

创建composer项目

# mkdir phoenix
# cd phoenix
composer init

phoenix是接下来搭建的框架名。

1

创建成功后,发现当前文件夹下会生成一个composer.json文件,里面是刚写入的内容。

composer dump

2

tree后,就会发现多了一个vendor的目录,里面的autoload.php以及composer文件夹下文件就是整个框架的加载核心

接下来看一遍这些文件。

在整个框架中,第一行必然要引用 vendor/autoload.php 文件,毕竟这是加载核心,那么就从autoload.php看起。

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

return ComposerAutoloaderInit599fa618dd1395bdde5fc3a08ff3e4e6::getLoader(); 

只调用了autoload_real.php里面的getLoader()方法。

#autoload_real.php 精简后的代码

public static function loadClassLoader($class)
{
    if ('Composer\Autoload\ClassLoader' === $class) {
        require __DIR__ . '/ClassLoader.php';
    }
}

public static function getLoader()
{
    #创建ClassLoader类
    spl_autoload_register(array('ComposerAutoloaderInit599fa618dd1395bdde5fc3a08ff3e4e6', 'loadClassLoader'), true, true);

    #初始化ClassLoader对象(主要就是将命名空间和文件的映射写入ClassLoader的属性中)
    self::$loader = $loader = new \Composer\Autoload\ClassLoader();

    spl_autoload_unregister(array('ComposerAutoloaderInit599fa618dd1395bdde5fc3a08ff3e4e6', 'loadClassLoader')); 
     
    #loadClass方法(类似autoload方法)注册到 SPL Autoload
    $loader->register(true);   
}

autoload_real.php 的作用就是引入ClassLoader类、初始化ClassLoader类,并注册到SPL堆栈中。

ClassLoader类中有很多属性,这些属性的作用也很简单:主要就是方便后面程序快速的通过命名空间找到它所映射的类文件

具体用到这些属性的方法就在ClassLoader类中。

# ClassLoader.php
# 一个快速找到文件的算法,很有意思,感兴趣的可以研究下
# 主要通过首字符找到命名空间以及长度,再根据命名空间以及长度找到文件

private function findFileWithExtension($class, $ext)
{
    ......
}

那么ClassLoader类属性里面的值是什么时候写入的呢?

答案很简单:当为项目安装组件时,即composer require xxx时,会更新ClassLoader类的属性值,也就是将命名空间和文件地址做一个关联

接下来看看它的register方法。

# ClassLoader.php 
public function register($prepend = false)
{
    spl_autoload_register(array($this, 'loadClass'), true, $prepend);
}

看,其实很简单,就是将loadClass注册到SPL堆栈中。

请关注公众号获取更多资料


一次框架性能的比较,引起了我对搭建web框架的兴趣(一) https://www.cppentry.com/bencandy.php?fid=97&id=272915

首页 上一页 1 2 3 4 5 6 7 下一页 尾页 1/7/7
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇设计模式随笔 下一篇k8s~跨namespace的service相互访问