如何提高自己编写代码的能力呢?作为web开发者,我们通常都是基于面向对象OOP来开发的,所以面向对象的设计能力或者说设计模式的运用能力尤为重要,当然还有开发语言本身特性和基础的灵活运用。我们可以去阅读一些优秀的开源项目,理解里面的代码设计,去学习和造轮子来提高自己。我比较关注web framework中的路由、HTTP、依赖注入容器这几部分,路由和http处理是web框架必不可少的,整个框架的服务对象依赖解析也是很重要的,有了依赖注入容器可以实现类很好的解耦。Dependency Injection Container先来说下什么是依赖注入,依赖注入是一种允许我们从硬编码的依赖中解耦出来,从而在运行时或者编译时能够修改的软件设计模式(来自维基百科 Wikipedia)。依赖注入通过构造注入,函数调用或者属性的设置来提供组件的依赖关系。下面的代码中有一个 Database 的类,它需要一个适配器来与数据库交互。我们在构造函数里实例化了适配器,从而产生了耦合。这会使测试变得很困难,而且 Database 类和适配器耦合的很紧密。<?phpnamespace Database;class Database{ protected $adapter; public function __construct() { $this->adapter = new MySqlAdapter; }}class MysqlAdapter {}这段代码可以用依赖注入重构,从而解耦<?phpnamespace 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); // truevar_dump($foo->bar instanceof Bar); // truevar_dump($foo->bar->baz instanceof Baz); // true2.方法注入<?phpdeclare(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); // truevar_dump($controller->model instanceof Model); // truevar_dump($controller->model->pdo instanceof \PDO); // true3.匿名回调函数注入<?phpdeclare(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); // truevar_dump($controller->model instanceof Model); // truevar_dump($controller->model->pdo instanceof \PDO); // true自动布线 (auto wiring)<?phpdeclare(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); // truevar_dump($foo->bar instanceof Bar); // truevar_dump($foo->baz instanceof Baz); // truevar_dump($foo->bar->bam instanceof Bam); // trueRoute再介绍下路由使用的例子,route可以使用symfony的http foundation组件来处理HTTP请求(http messages)。<?phprequire ‘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;其它的ORM、cache、filesystem、session、validation等组件可以使用composer来由用户自由扩展。项目地址 https://github.com/parvinShi/…
...