内容简介:如何提高自己编写代码的能力呢?作为web开发者,我们通常都是基于面向对象OOP来开发的,所以面向对象的设计能力或者说设计模式的运用能力尤为重要,当然还有开发语言本身特性和基础的灵活运用。我们可以去阅读一些优秀的开源项目,理解里面的代码设计,去学习和造轮子来提高自己。我比较关注web framework中的路由、HTTP、依赖注入容器这几部分,路由和http处理是web框架必不可少的,整个框架的服务对象依赖解析也是很重要的,有了依赖注入容器可以实现类很好的解耦。
如何提高自己编写代码的能力呢?作为web开发者,我们通常都是基于面向对象OOP来开发的,所以面向对象的设计能力或者说 设计模式 的运用能力尤为重要,当然还有开发语言本身特性和基础的灵活运用。
我们可以去阅读一些优秀的开源项目,理解里面的代码设计,去学习和造轮子来提高自己。
我比较关注web framework中的路由、HTTP、依赖注入容器这几部分,路由和http处理是web框架必不可少的,整个框架的服务对象依赖解析也是很重要的,有了依赖注入容器可以实现类很好的解耦。
Dependency Injection Container
先来说下什么是依赖注入,依赖注入是一种允许我们从硬编码的依赖中解耦出来,从而在运行时或者编译时能够修改的软件设计模式(来自维基百科 Wikipedia)。
依赖注入通过构造注入,函数调用或者属性的设置来提供组件的依赖关系。
下面的代码中有一个 Database 的类,它需要一个适配器来与数据库交互。我们在构造函数里实例化了适配器,从而产生了耦合。这会使测试变得很困难,而且 Database 类和适配器耦合的很紧密。
<?php namespace Database; class Database { protected $adapter; public function __construct() { $this->adapter = new MySqlAdapter; } } class MysqlAdapter {}
这段代码可以用依赖注入重构,从而解耦
<?php namespace Database; class Database { protected $adapter; public function __construct(MySqlAdapter $adapter) { $this->adapter = $adapter; } } class MysqlAdapter {}
现在我们通过外界给予 Database 类的依赖,而不是让它自己产生依赖的对象。我们甚至能用可以接受依赖对象参数的成员函数来设置,或者如果 $adapter 属性本身是 public的,我们可以直接给它赋值。
根据依赖注入的概念,我们的框架实现了这些特性,代码如下。
Dependency injection Container基于PSR-11规范实现,包括3种注入实现方式:构造方法注入(Constructor Injection)、setter方法或属性注入(Setter Injection)、匿名回调函数注入。
1.构造方法注入(Constructor Injection)
<?php 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.方法注入
<?php 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.匿名回调函数注入
<?php 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)
<?php 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组件来处理HTPP消息请求(http messages)。
<?php 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; }); $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;
以上所述就是小编给大家介绍的《为了学习理解依赖注入和路由,自己撸了一个框架》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 三, 跨语言微服务框架 - Istio官方示例(自动注入.请求路由.流量控制.故障注入) 原 荐
- vue路由篇(动态路由、路由嵌套)
- 小程序封装路由文件和路由方法,5种路由方法全解析
- Vue的路由及路由钩子函数
- gin 源码阅读(二)-- 路由和路由组
- Angular 4 依赖注入教程之二 组件中注入服务
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。