自制 PHP 小框架 FanlyPHP 之插件选择
Posted coding01
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自制 PHP 小框架 FanlyPHP 之插件选择相关的知识,希望对你有一定的参考价值。
参考 Laravel 整个源代码,可以发现 Laravel 框架借用了很多第三方优质插件:
"require": {
"php": "^7.1.3",
"ext-json": "*",
"ext-mbstring": "*",
"ext-openssl": "*",
"doctrine/inflector": "^1.1",
"dragonmantank/cron-expression": "^2.0",
"egulias/email-validator": "^2.0",
"erusev/parsedown": "^1.7",
"league/flysystem": "^1.0.8",
"monolog/monolog": "^1.12",
"nesbot/carbon": "^1.26.3 || ^2.0",
"opis/closure": "^3.1",
"psr/container": "^1.0",
"psr/simple-cache": "^1.0",
"ramsey/uuid": "^3.7",
"swiftmailer/swiftmailer": "^6.0",
"symfony/console": "^4.2",
"symfony/debug": "^4.2",
"symfony/finder": "^4.2",
"symfony/http-foundation": "^4.2",
"symfony/http-kernel": "^4.2",
"symfony/process": "^4.2",
"symfony/routing": "^4.2",
"symfony/var-dumper": "^4.2",
"tijsverkoyen/css-to-inline-styles": "^2.2.1",
"vlucas/phpdotenv": "^3.3"},
通过不同插件的作用,来构造满足自己框架设计的目标。今天我也沿用这个做法,寻找一些不错的 PHP 插件。
正如之前所说,我给这个自制小框架取名:FanlyPHP。
首先,public 文件夹用于存放入口文件 index.php
,写个 demo:
<?php
echo "你好,FanlyPHP";
使用 php -S localhost:1234
命令执行看看效果:
创建 composer.json 文件用于添加我们的第三方插件。
用命令行 composer init
根据提示初始化 composer.json 内容:
{
"name": "coding01/fanlyphp",
"description": "The Coding01 Framework for PHP.",
"type": "project",
"license": "MIT",
"authors": [
{
"name": "coding01",
"email": "yemeishu@126.com"
}
],
"require": {}
}
composer install
就会多一个 vendor
文件夹用于存放第三方插件。
创建 app 文件夹用于存放我们的代码,和 Laravel 的结构相似。并引入进 composer.json,按 psr-4 自动加载。记得要执行下命令:composer dump-autoload。
下面我们一个个来分析这几个插件的使用。
A simple but powerful dependency injection container.
http://container.thephpleague.com/
这个插件主要会引入 DI Container,也是本文推荐的,而且 nikic/fast-route
也是 Lumen 使用的。
写个 demo
先创建一个service demo 类
<?php
/**
* User: yemeishu
* Date: 2019/5/15
* Time: 下午8:37
*/
namespace App;
class ServiceDemo{
public function hello()
{
return "叶梅树的 service demo";
}
}
在 index.php
引入 autoload.php
,这样就可以自动发现 composer 第三方包。
<?php
require_once __DIR__.'/../vendor/autoload.php';
$container = new LeagueContainerContainer;
// add a service to the container
$container->add('service', 'AppServiceDemo');
// retrieve the service from the container
$service = $container->get('service');
echo $service->hello();
$demo = new AppServiceDemo();
echo $demo->hello();
执行结果:
可以看出利用 Container
和 new AppServiceDemo()
,效果一致。
Route is a fast routing/dispatcher package enabling you to build well designed performant web apps. At its core is Nikita Popov’s FastRoute package allowing this package to concentrate on the dispatch of your controllers.
http://route.thephpleague.com/
composer require league/route
根据官网的提示,还需要安装一个插件:
composer require zendframework/zend-diactoros
写个 demo
在上文例子的基础上,增加 route 的代码,具体看代码,比较简单:
<?php
use PsrHttpMessageResponseInterface;
use PsrHttpMessageServerRequestInterface;
require_once __DIR__.'/../vendor/autoload.php';
$container = new LeagueContainerContainer;
// add a service to the container
$container->add('service', 'AppServiceDemo');
// retrieve the service from the container
$service = $container->get('service');
$container->share('response', ZendDiactorosResponse::class);
$container->share('request', function () {
return ZendDiactorosServerRequestFactory::fromGlobals(
$_SERVER,
$_GET,
$_POST,
$_COOKIE,
$_FILES
);
});
$container->share('emitter', ZendDiactorosResponseSapiEmitter::class);
$route = new LeagueRouteRouteCollection($container);
$route->map(
'GET',
'/demo',
function (ServerRequestInterface $request, ResponseInterface $response
) use ($service) {
$hello = $service->hello();
$response->getBody()->write("<h1>$hello</h1>");
return $response;
}
);
$response = $route->dispatch($container->get('request'), $container->get('response'));
$container->get('emitter')->emit($response);
看效果,路由指定到 http://localhost:1234/demo
:
This package provides a plug and play implementation of the Pipeline Pattern. It’s an architectural pattern which encapsulates sequential processes. When used, it allows you to mix and match operation, and pipelines, to create new execution chains. The pipeline pattern is often compared to a production line, where each stage performs a certain operation on a given payload/subject. Stages can act on, manipulate, decorate, or even replace the payload.
If you find yourself passing results from one function to another to complete a series of tasks on a given subject, you might want to convert it into a pipeline.
https://pipeline.thephpleague.com/
// 安装插件
composer require league/pipeline
写个 demo
use LeaguePipelinePipeline;
// 创建两个闭包函数
$pipe1 = function ($payload) {
return $payload + 1;
};
$pipe2 = function ($payload) {
return $payload * 3;
};
$route->map(
'GET',
'/demo',
function (ServerRequestInterface $request, ResponseInterface $response
) use ($service, $pipe1, $pipe2) {
$params = $request->getQueryParams();
// 引入闭包函数
$pipeline = (new Pipeline)
->pipe($pipe1)
->pipe($pipe2);
// 执行
$callback = $pipeline->process($params['data']);
$hello = $service->hello();
$response->getBody()->write("<h1>$hello, $callback</h1>");
return $response;
}
);
与 Laravel 相似,我们借助 .env
来保存我们的配置信息。
安装插件
composer require vlucas/phpdotenv
写个 demo
$dotenv = new DotenvDotenv(__DIR__."/../");
$dotenv->load();
$route->map(
'GET',
'/env_demo',
function (ServerRequestInterface $request, ResponseInterface $response
) {
$data = getenv('hello');
$response->getBody()->write("<h1>使用 env</h1>");
$response->getBody()->write("<p>$data</p>");
return $response;
}
);
看看 .env
定义的值
hello=Fanly
看执行结果:
GraphQL 是一种现代化的 HTTP API 接口构建方式,是 Facebook 在 2012 年开发的,2015 年开源,2016 年下半年 Facebook 宣布可以在生产环境使用,而其内部早就已经广泛应用了。GraphQL 是作为一个 REST 和 SOAP API 的替代品来设计的,Facebook 应对复杂接口查询的方案非常简单:用一个 “聪明” 的节点来进行复杂查询,将数据按照客户端的要求传回去,后端根据 GraphQL 机制提供一个具有强大功能的接口,用以满足前端数据的个性化需求,既保证了多样性,又控制了接口数量。
参考:https://laravel-china.org/docs/graphql-php
安装插件
composer require webonyx/graphql-php
写个 demo
在上面的例子,我们结合 GraphQL:
首先定义一个 QueryType
:
$queryType = new ObjectType([
'name' => 'HelloQuery',
'fields' => [
'hello' => [
'type' => Type::string(),
'args' => [
'message' => ['type' => Type::string()],
],
'resolve' => function ($root, $args) {
return $root['prefix'] . $args['message'];
}
],
],
]);
添加进 Schema
中
$schema = new Schema([
'query' => $queryType
]);
增加 route
:
$route->map(
'POST',
'/graphql_demo',
function (
ServerRequestInterface $request,
ResponseInterface $response
) use (
$queryType,
$schema
) {
$params = $request->getParsedBody();
$collect = collect($params);
$rootValue = ['prefix' => 'from: '];
try {
$result = GraphQL::executeQuery($schema, $collect->get('query'), $rootValue);
$output = json_encode($result->toArray());
} catch (Exception $e) {
$output = [
'error' => [
'message' => $e->getMessage()
]
];
}
$response->getBody()->write("<h1>输出结果</h1>");
$response->getBody()->write("<p>$output</p>");
return $response;
}
);
重点是该语句:$result = GraphQL::executeQuery($schema, $collect->get('query'), $rootValue);
运行结果如下:
如果传入的参数不对,看看显示效果:
如,我一直是 Laravel's Collections
的忠实粉丝,所以在框架中必然会引入 collect
,所以本框架选用 tightenco/collect
:
A Collections-only split from Laravel's Illuminate Support
具体参考:https://github.com/tightenco/collect
还有其它插件安装
// 时间处理插件
composer require nesbot/carbon
// Log 插件
composer require monolog/monolog
插件的使用满足于我们不用自己再去造轮子了,如何合理有效的使用这些插件,就看接下来如何规划框架结构了,推荐看看有关 MVC 相关书籍内容。
以上是关于自制 PHP 小框架 FanlyPHP 之插件选择的主要内容,如果未能解决你的问题,请参考以下文章