php 依赖注入框架,通过实现依赖注入和路由,构建一个自己的现代化PHP框架
如何提高自己编写代码的能力呢?我们首先想到的是阅读学习优秀的开源项目,然后写一个自己的web框架或类库组件。作为web开发者,我们通常都是基于面向对象OOP来开发的,所以面向对象的设计能力或者说设计模式的运用能力尤为重要,当然还有开发语言本身特性和基础的灵活运用。
我们可以去阅读一些优秀的开源项目,理解里面的代码设计,去学习和造轮子来提高自己。
在优秀成熟的web framework中,路由和http处理是web框架必不可少的,整个框架的服务对象依赖解析也是很重要的,有了依赖注入容器可以实现类很好的解耦。
依赖注入容器 Dependency Injection Container
先来说下什么是依赖注入,依赖注入是一种允许我们从硬编码的依赖中解耦出来,从而在运行时或者编译时能够修改的软件设计模式(来自维基百科 Wikipedia)。
依赖注入通过构造注入,函数调用或者属性的设置来提供组件的依赖关系。
下面的代码中有一个 Database 的类,它需要一个适配器来与数据库交互。我们在构造函数里实例化了适配器,从而产生了耦合。这会使测试变得很困难,而且 Database 类和适配器耦合的很紧密。
namespace Database;
class Database
{
protected $adapter;
public function __construct()
{
$this->adapter = new MySqlAdapter;
}
}
class MysqlAdapter {}
这段代码可以用依赖注入重构,从而解耦
namespace Database;
class Database
{
protected $adapter;
public function __construct(MySqlAdapter $adapter)
{
$this->adapter = $adapter;
}
}
class MysqlAdapter {}
现在我们通过外界给予 Database 类的依赖,而不是让它自己产生依赖的对象。我们甚至能用可以接受依赖对象参数的成员函数来设置,或者如果 $adapter 属性本身是 public的,我们可以直接给它赋值。
根据依赖注入的概念,我们的框架实现了这些特性。
Dependency injection Container基于PSR-11规范实现,使用了PHP的类反射功能,去实例化类定义的对象依赖。定义类的对象依赖包括3种注入实现方式:构造方法注入(Constructor Injection)、setter方法或属性注入(Setter Injection)、匿名回调函数注入,代码示例如下:
1.构造方法注入(Constructor Injection)
declare(strict_types=1);
namespace Examples;
use Eagle\DI\Container;
class Foo
{
/**
* @var \Examples\Bar
*/
public $bar;
/**
* Foo constructor.
* @param \Examples\Bar $bar
*/
public function __construct(Bar $bar)
{
$this->bar = $bar;
}
}
/*class Bar {
}*/
class Bar {
public $baz;
public function __construct(Baz $baz)
{
$this->baz = $baz;
}
}
class Baz {
}
$container = new Container;
$container->set(Foo::class)->addArguments(Bar::class);
$container->set(Bar::class)->addArguments(Baz::class);
$foo = $container->get(Foo::class);
var_dump($foo, $foo->bar);
var_dump($foo instanceof Foo); // true
var_dump($foo->bar instanceof Bar); // true
var_dump($foo->bar->baz instanceof Baz); // true
2.方法注入(Setter Injection)
declare(strict_types=1);
namespace Examples;
require 'vendor/autoload.php';
use Eagle\DI\Container;
class Controller
{
public $model;
public function __construct(Model $model)
{
$this->model = $model;
}
}
class Model
{
public $pdo;
public function setPdo(\PDO $pdo)
{
$this->pdo = $pdo;
}
}
$container = new Container;
$container->set(Controller::class)->addArguments(Model::class);
$container->set(Model::class)->addInvokeMethod('setPdo', [\PDO::class]);
$container->set(\PDO::class)
->addArguments(['mysql:dbname=test;host=localhost', 'root', '111111']);
$controller = $container->get(Controller::class);
var_dump($controller instanceof Controller); // true
var_dump($controller->model instanceof Model); // true
var_dump($controller->model->pdo instanceof \PDO); // true
3.匿名回调函数注入(Closure callable Injection)
declare(strict_types=1);
namespace Examples;
require 'vendor/autoload.php';
use Eagle\DI\Container;
class Controller
{
public $model;
public function __construct(Model $model)
{
$this->model = $model;
}
}
class Model
{
public $pdo;
public function setPdo(\PDO $pdo)
{
$this->pdo = $pdo;
}
}
$container = new Container;
$container->set(Controller::class, function () {
$pdo = new \PDO('mysql:dbname=test;host=localhost', 'root', '111111');
$model = new Model;
$model->setPdo($pdo);
return new Controller($model);
});
$controller = $container->get(Controller::class);
var_dump($controller instanceof Controller); // true
var_dump($controller->model instanceof Model); // true
var_dump($controller->model->pdo instanceof \PDO); // true
自动装配(auto wiring)
declare(strict_types=1);
namespace AutoWiring;
require 'vendor/autoload.php';
use Eagle\DI\ContainerBuilder;
class Foo
{
/**
* @var \AutoWiring\Bar
*/
public $bar;
/**
* @var \AutoWiring\Baz
*/
public $baz;
/**
* Construct.
*
* @param \AutoWiring\Bar $bar
* @param \AutoWiring\Baz $baz
*/
public function __construct(Bar $bar, Baz $baz)
{
$this->bar = $bar;
$this->baz = $baz;
}
}
class Bar
{
/**
* @var \AutoWiring\Bam
*/
public $bam;
/**
* Construct.
*
* @param \AutoWiring\Bam $bam
*/
public function __construct(Bam $bam)
{
$this->bam = $bam;
}
}
class Baz
{
// ..
}
class Bam
{
// ..
}
$container = new ContainerBuilder;
$container = $container->build();
$foo = $container->get(Foo::class);
var_dump($foo instanceof Foo); // true
var_dump($foo->bar instanceof Bar); // true
var_dump($foo->baz instanceof Baz); // true
var_dump($foo->bar->bam instanceof Bam); // true
路由 Route
再介绍下路由的使用,route可以使用symfony的http foundation组件来处理HTTP请求(http messages)。
require 'vendor/autoload.php';
use Eagle\Route\Router;
use Symfony\Component\HttpFoundation\Request;
$router = new Router();
$router->get('/articles', function () {
return 'This is articles list';
});
$router->get('/articles/{id:\d+}', function ($id) {
return 'Article id: ' . $id;
});
/* title为可选参数 */
$router->get('/articles/{id:\d+}[/{title}]', function ($id, $title) {
return 'Article id: ' . $id . ', title: ' . $title;
});
/*匹配处理路由组*/
$router->group('/articles', function () use ($router) {
$router->get('/list', function() {
return 'This is articles list';
});
$router->get('/detail', function ($id, $title) {
return 'Article detail id: ' . $id . ', title: ' . $title;
});
});
$request = new Request();
$routeHandler = $router->getRouteHandler();
$response = $routeHandler->handle($request);
echo $response;
其它的ORM、cache、filesystem、session、validation等组件可以使用composer来由用户自由扩展。
相关文章:

针对七牛含有特殊字符的文件名,对特殊字符编码处理
源字符串: a a 1 ~!#$%^&()_-{}[];,.- 编码后: a%20a%201%20~%60%21%23$%25%5E&%28%29_-%7B%7D%5B%5D;%27,.-%20 源字符串: 变 ~!#¥%…………&()——-{}:“;‘、《》?&…

linux sftp权限设置,Linux设置SFTP服务用户目录权限
我们有时会遇到这样的需求,限制一个Linux用户,让他只能在指定的目录下进行添加、修改、删除操作,并且只能使用sftp登录服务器,不能用ssh操作。这些可以通过配置sftp服务实现。提供sftp服务的有vsftpd和internal-sftp,这…

mybatis动态sql中的trim标签的使用
trim标记是一个格式化的标记,可以完成set或者是where标记的功能,如下代码: 1、 select * from user <trim prefix"WHERE" prefixoverride"AND |OR"> <if test"name ! null and name.length()>0"&…

smarty mysql demo_PHP Smarty模版简单使用方法
本文实例讲述了PHP Smarty模版简单使用方法。分享给大家供大家参考,具体如下:Index.php:require(../libs/Smarty.class.php);$smarty new Smarty;// 添加自定义调节器$smarty->registerPlugin("modifier", "e", &quo…

php webuploader大文件,web uploader 上传大文件总结
由于业务需要,需要上传大文件,已有的版本无法处理IE版本,经过调研,百度的 webuploader 支持 IE 浏览器,而且支持计算MD5值,进而可以实现秒传的功能。大文件上传主要分为三部分,预上传࿰…

cfl3d linux 编译,CMake build system for cfl3d
-0,0 1,379 ---title: cfl3dopenmpigfortran编译和安装---#简介cfl3d用intel的编译器和mpi会比较容易编译,不再详述。本文主要讲述用gfortran的情况cfl3d依赖于cgns, fortran编译器和mpi- mpi:只要是符合mpi1.1的标准的MPI应该都可以的,mpich, openmpi, …

Request.getInputStrema只能读取一次的分析过程
1. 我们先来看一下继承关系HttpServletRequest 接口继承ServletRequest接口 public abstract interface ServletRequest{ public abstract ServletInputStream getInputStream() throws IOException; } 从上面可知request.getInputStream()返回的是ServletInputSt…

windows nodejs mysql_windows server 安装 mysql + nondejs连接mysql
下载安装下载完后,将 zip 包解压到相应的目录,这里我将解压后的文件夹放在 C:\mysql 下。接下来需要配置下 MySQL 的配置文件打开刚刚解压的文件夹 C:\mysql ,在该文件夹下创建 my.ini 配置文件,编辑 my.ini 配置以下基本信息&…

多线程并行和并发的区别
并行就是两个任务同时运行,就是甲任务进行的同时,乙任务也在进行。(需要多核CPU) 并发是指两个任务都请求运行,而处理器只能按受一个任务,就把这两个任务安排轮流进行,由于时间间隔较短,使人感觉两个任务都…

php dropdownlist,为何activitieDropdownlist的值始终无法获取到
为什么activitieDropdownlist的值始终无法获取到?视图层view控制器层public function actionDbdplist(){$m_subjectlist new SubjectList();$m_gradelist new Grade;$this->subject_list SubjectList::model()->findAll();$this->grade_list Grade::mo…

python之内置函数
一、 内置函数 什么是内置函数?就是python给你提供的可以直接使用的函数。到目前为止在python中一共有68个内置函数 经过我两个多小时的制作终于弄出了个能看的东西↓↓↓↓↓↓ 思维导图链接:https://www.processon.com/view/link/5b72a285e4b053a09c33e534 转载于…

远程桌面linux服务器配置,linux平台下远程桌面服务器的安装和设置
一、xdm 方式前提:安装linux时一定要选上xwindow,这是最基本的前提,不安装它,是绝对没有图形界面的。**********************************************************基本概念和相关命令说明:XDMCP(X Display Manager Co…

关于字符串的分割问题
1、如何快速的将一个字符串分割成一个个字符? Scanner scnew Scanner(System.in);System.out.println("请输入一个字符串:");String strsc.next();System.out.println("输入的字符串的长度为:"str.length());char [] ast…

java创建对象_java 创建对象的五种方式
通过 Class 对象的 getConstructor 可以获取 java.lang.reflect.Constructor 对象Constructor 对象用来描述类的构造方法,通过给 getConstructor 方法传入不同的 Class 对象,可以获取到对应的无参或有参数的构造方法通过 Constructor 的 newInstance 方法…

php拍照从手机相册中选择,微信js-sdk预览图片接口及从拍照或手机相册中选图接口用法示例...
本文实例讲述了微信js-sdk预览图片接口及从拍照或手机相册中选图接口用法。分享给大家供大家参考,具体如下:目前中js-sdk 1.0版本中,预览图片提供了2个接口,接口的定义参考官方文档1.预览网络图片http链接的2.预览本地图片wenxin:…

BZOJ 1124: [POI2008]枪战Maf(构造 + 贪心)
题意 有 \(n\) 个人,每个人手里有一把手枪。一开始所有人都选定一个人瞄准(有可能瞄准自己)。然后他们按某个顺序开枪,且任意时刻只有一个人开枪。 因此,对于不同的开枪顺序,最后死的人也不同。 问最后死的…

Maven跳过测试
Maven跳过测试用例 在properties中声明<properties><maven.test.skip>true</maven.test.skip> </properties> 或者 <properties><skipTests>true</skipTests> </properties> 在执行命令中声明mvn test -Dmaven.test.skiptrue …

Linux内核 题目,《Linux内核完全注释》部分习题答案
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼第3章 内核引导和启动过程2.为什么不直接将system模块搬到0x00000处而是先搬到0x10000处,再搬到0x00000处呢?在机器开机上电时,ROM BIOS将bootsect代码加载到内存的固定位置0x7c00处,…

java jdk 1.8 安装_下载、安装、配置 java jdk1.8
近期配置react native的开发环境,所以就从配置环境开始。rn的环境配置有那么几项,其中重要的一个就是java jdk(Java Development Kit 的缩写),那么以下就是下载、安装还有配置的流程1.下载java jdk 1.8在地址栏输入 java jdk,如下图所示&…

liunx php redis扩展,CentOS 7下安装php-redis扩展及简单使用
前言:在本篇文章中,我将给大家介绍如何在CentOS7上安装PHP-Redis扩展以及一些简单的实用,关于如何在Centos上安装redis的,可以参考想要在php中操作redis,那就必须安装php-redis扩展,就比如MySQL一样&#x…

Luogu 2470 [SCOI2007]压缩
和Luogu 4302 [SCOI2003]字符串折叠 差不多的想法,区间dp 为了计算方便,我们可以假设区间[l, r]的前面放了一个M,设$f_{i, j, 0/1}$表示区间$[i, j]$中是否存在M 因为这题只能是二的幂次倍压缩,所以转移的时候枚举中点chk是否合法…

做图形处理Linux小型主机,8个优秀的linux图形图像工具
对艺术家、摄影师、动画师和设计师而言,Linux是一个有潜力的平台。廉价的硬件,优秀的免费软件,任何有才华的人都能在上面创作专业水平的计算机图形。开源社区提供了丰富的开源图形工具,但要慧眼识珠并非易事。这里介绍的优秀图形工…

使用laravel框架的eloquent\DB模型连接多个数据库
1、配置.env文件 DB_HOST_TRAILER127.0.0.1DB_PORT_TRAILER3306DB_DATABASE_TRAILERhtms_trailerDB_USERNAME_TRAILERrootDB_PASSWORD_TRAILER DB_HOST_FREIGHT127.0.0.1DB_PORT_FREIGHT3306DB_DATABASE_FREIGHThangli_saasDB_USERNAME_FREIGHTrootDB_PASSWORD_FREIGHT 2、配置…

java openfile busy_android java.io.IOException: open failed: EBUSY (Device or resource busy)
今天遇到一个奇怪的问题,测试在程序的下载界面,下载一个文件第一次下载成功,删除后再下载结果下载报错,程序:file.createNewFile();报错:java.io.IOException: open failed: EBUSY (Device or resource bus…

java service注入失败,使用spring向service里面注入dao不成功。
使用spring向service里面注入dao不成功。求救啊!本帖最后由 PaperStar 于 2013-12-26 19:29:20 编辑页面调用action,action调用service,service调用dao用Debug查看action调用service方法时service有值,但是service调用dao时&#…

下面为初学者分享一下SQL 数据库学习资料
一、基础1、说明:创建数据库CREATE DATABASE database-name2、说明:删除数据库drop database dbname3、说明:备份sql server--- 创建 备份数据的 deviceUSE masterEXEC sp_addumpdevice disk, testBack, c:\mssql7backup\MyNwind_1.dat--- 开…

linux7设置时间,CentOS 7 设置日期和时间
现代操作系统分为以下两种类型的时钟:实时时钟(Real-Time Clock,RTC),通常称为硬件时钟(一般是系统主板上的集成电路),它完全独立于操作系统的当前状态,即使在计算机关闭时也能运行。系统时钟,也称为软件时…

SQLMap安装步骤
SQLMap是利用Python语言写的,所以需要将Python这个语言环境给安装上 : 1、首先下载Python(这里Python版本为2.7.2,可以下载不同或高版本的) 2、然后在下载sqlmap(http://sqlmap.org) 3、这两个软件下载完成后ÿ…

am5718_AM5718如何扩大内存 - Sitara™ Cortex-A8 和 ARM9 微处理器 - Sitara™ Cortex-A8 和 ARM9 微处理器 - E2E™ 中文支持论坛...
谢谢了Shine,你的资料和建议非常到位,按您的建议,修改了board.c以下两处,问题解决了。1:board/ti/am57xx/board.c文件static const struct dmm_lisa_map_regs am571x_idk_lisa_regs {.dmm_lisa_map_3 0x80640100,.is_ma_present…

亚马逊刊登php代码,最全的亚马逊刊登listing工具了解一下
如果你是亚马逊FBA卖家,那么你可能会错过很多有用的亚马逊listing工具。这些listing工具可以批量上传listing,同时还可以记录产品特征,以及打印运输标签。1、易仓刊登系统易仓刊登系统是一款易仓基于已有ERP客户需求研发的一套平台产品刊登系…