2016 年 10 月 QueryPHP 开始基于以前的一个过气老 php.5.0-5.4 版本框架进行重构,经过两年的开发项目终于接近尾声。随着单元测试逐步逼近 100%,第一个 alpha 版本正在整理发布。
根据以前的计划,我希望做一个这样的框架,首先它是一个传统的 PHP 框架,无须依赖任何扩展,很容易安装。
首先它应该是团队友好
为每一个 PHP 脚本开启强类型,提高代码质量,严禁意味着后期更少的错误
<?php
declare(strict_types=1);
/*
* This file is part of the ************************ package.
* _____________ _______________
* ______/ \__ _____ ____ ______ / /_ _________
* ____/ __ / / / / _ \/ __`\/ / __ \/ __ \/ __ \___
* __/ / / / /_/ / __/ / \ / /_/ / / / / /_/ /__
* \_\ \_/\____/\___/_/ / / .___/_/ /_/ .___/
* \_\ /_/_/ /_/
*
* The PHP Framework For Code Poem As Free As Wind. <Query Yet Simple>
* (c) 2010-2018 http://queryphp.com All rights reserved.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Leevel\Kernel;
use Leevel\Http\IRequest;
use Leevel\Http\IResponse;
/**
* 内核执行接口.
*
* @author Xiangmin Liu <635750556@qq.com>
*
* @since 2016.11.18
*
* @version 1.0
*/
interface IKernel
{
/**
* 响应 HTTP 请求
*
* @param \Leevel\Http\IRequest $request
*
* @return \Leevel\Http\IResponse
*/
public function handle(IRequest $request): IResponse;
/**
* 执行结束
*
* @param \Leevel\Http\IRequest $request
* @param \Leevel\Http\IResponse $response
*/
public function terminate(IRequest $request, IResponse $response): void;
/**
* 返回项目.
*
* @return \Leevel\Kernel\IProject
*/
public function getProject(): IProject;
}
单元测试高覆盖
我发现国内很多 PHP 框架竟然是 0 单元测试,随着我自己开始编写越来越多的单元测试,发现了单元测试不仅仅是发现 bug,更是可以帮助你设计框架接口,站在使用者的立场来优化框架组件。而且对于后期将会生成良性循环,更少 bug 减少反反复复地陷入无法自拔,代码质量无法保证,所以 QueryPHP 第一个版本基本维度 100% 覆盖,后续加强。
<?php
declare(strict_types=1);
/*
* This file is part of the ************************ package.
* _____________ _______________
* ______/ \__ _____ ____ ______ / /_ _________
* ____/ __ / / / / _ \/ __`\/ / __ \/ __ \/ __ \___
* __/ / / / /_/ / __/ / \ / /_/ / / / / /_/ /__
* \_\ \_/\____/\___/_/ / / .___/_/ /_/ .___/
* \_\ /_/_/ /_/
*
* The PHP Framework For Code Poem As Free As Wind. <Query Yet Simple>
* (c) 2010-2018 http://queryphp.com All rights reserved.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Tests\Cache;
use Leevel\Cache\File;
use Tests\TestCase;
/**
* file test.
*
* @author Xiangmin Liu <635750556@qq.com>
*
* @since 2018.06.05
*
* @version 1.0
*/
class FileTest extends TestCase
{
}
良好的体验
QueryPHP 以 Laravel 和 Symfony 为参考对象,主打 ioc + ddd 方式来构建良好用户体验的框架。orm 在做小规模重构,相关设计在试错中。
<?php
declare(strict_types=1);
/*
* This file is part of the ************************ package.
* _____________ _______________
* ______/ \__ _____ ____ ______ / /_ _________
* ____/ __ / / / / _ \/ __`\/ / __ \/ __ \/ __ \___
* __/ / / / /_/ / __/ / \ / /_/ / / / / /_/ /__
* \_\ \_/\____/\___/_/ / / .___/_/ /_/ .___/
* \_\ /_/_/ /_/
*
* The PHP Framework For Code Poem As Free As Wind. <Query Yet Simple>
* (c) 2010-2018 http://queryphp.com All rights reserved.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Tests\Database\Ddd\Entity;
use Leevel\Database\Ddd\Entity;
/**
* TestConstructWhiteEntity.
*
* @author Xiangmin Liu <635750556@qq.com>
*
* @since 2018.06.30
*
* @version 1.0
*/
class TestConstructWhiteEntity extends Entity
{
const TABLE = 'test';
/**
* 存在复合主键.
*
* @var array
*/
const PRIMARY_KEY = [
'id',
];
const AUTO_INCREMENT = 'id';
const STRUCT = [
'id' => [
'name' => 'id', // database
'type' => 'int', // database
'length' => 11, // database
'primary_key' => true, // database
'auto_increment' => true, // database
'default' => null, // database
'construct_white' => true,
],
'name' => [
'name' => 'name',
'type' => 'varchar',
'length' => 45,
'primary_key' => false,
'auto_increment' => false,
'default' => null,
],
];
protected $id;
protected $name;
}
组件化
每一个组件即是一个 composer, 遵循高内聚低耦合。
https://github.com/queryyetsimple
可选扩展框架实现高性能 Leevel
我们访问一个类, composer 根据 psr4 规则去搜索到我们文件而载入,如下的脚本会被载入。
https://github.com/hunzhiwange/framework/blob/master/src/Queryyetsimple/Di/Container.php
use Leevel\Di\Container
如果我们存在一个扩展就提供了这样一个类并随着 PHP 常驻,是不是性能不错,实际上是可以,QueryPHP 选择了 zephir 来实现。
https://github.com/hunzhiwange/leevel/blob/master/leevel/di/container.zep
实际上会被编译成 c
https://github.com/hunzhiwange/leevel/blob/master/ext/leevel/di/container.zep.c
这样子,不需要修改代码直接提升性能。
extension = leevel.so
opcache 开启后还有性能优化吗?
Yes, QueryPHP 的 PHP 版本和扩展版本功能一致,根据有对比性,核心组件走扩展来提升性能。 你可以亲自去编译一下。
https://github.com/hunzhiwange/leevel
如何保证 PHP 版本和扩展版本在对外 API 的一致性
高单元测试覆盖率,公用一份单元测试,我们通过 subtree 将单元测试抽离到一个 git 仓库来共享单元测试。
git subtree add --prefix=tests git@github.com:queryyetsimple/tests.git master
https://github.com/hunzhiwange/leevel/blob/master/tests/Di/ContainerTest.php
https://github.com/hunzhiwange/framework/blob/master/tests/Di/ContainerTest.php
超高性能支持 swoole
swoole 的问世对于 PHP 后端来说是一种福音,看到 swoole 4.1 开始支持原始 pdo,redis 协程,支持 swoole 势在必行。已经做了一些基础工作,对于第一个版本我们要完善单元测试,所以下一个版本以及未来数年主要支持 swoole.我们不想在传统的框架与 TP 竞争,不会疯狂扩展功能。稳定与性能是第一个要素,QueryPHP 志在高性能。未来主要围绕着微服务,与微服务基础设施进行整合的相关研究。
体验吧。求 star
访问
https://github.com/hunzhiwange/queryphp
composer create-project hunzhiwange/queryphp myapp dev-master --repository=https://packagist.org/
php leevel server <Visite http://127.0.0.1:9527/>
Api Test http://127.0.0.1:9527/api/test
php leevel link:public http://127.0.0.1:9527/public/css/page.css
php leevel link:storage http://127.0.0.1:9527/storage/logo.png
php leevel link:apis http://127.0.0.1:9527/apis/
优化性能
php leevel production
开启 opcache
更高性能,编译安装配套可选扩展
https://github.com/hunzhiwange/leevel
git clone git@github.com:hunzhiwange/leevel.git
cd ext
$/path/to/phpize
$./configure --with-php-config=/path/to/php-config
$make && make install
extension = leevel.so
来体验吧,如果你觉得有意思,给我一个 star,关注 QueryPHP.