php如何实现一个轻量级容器(代码示例)

php如何实现一个轻量级容器(代码示例)

内容导读

收集整理的这篇技术教程文章主要介绍了php如何实现一个轻量级容器(代码示例),小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含5367字,纯文字阅读大概需要8分钟

内容图文

本篇文章给大家带来的内容是关于php如何实现一个轻量级容器(代码示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

什么是容器

在开发过程中,经常会用到的一个概念就是依赖注入。我们借助依懒注入来解耦代码,选择性的按需加载服务,而这些通常都是借助容器来实现。

容器实现对对象的统一管理,并且确保对象实例的唯一性

容器可以很轻易的找到有很多实现示例,如 PHP-DI 、 YII-DI 等各种实现,通常他们要么大而全,要么高度适配特定业务,与实际需要存在冲突。

出于需要,我们自己造一个轻量级的轮子,为了保持规范,我们基于 PSR-11 来实现。

PSR-11

PSR 是 php-fig 提供的标准化建议,虽然不是官方组织,但是得到广泛认可。PSR-11 提供了容器接口。它包含 ContainerInterface 和 两个异常接口,并提供使用建议。

/** * Describes the interface of a container that exposes methods to read its entries. */interface ContainerInterface{

/**

 * Finds an entry of the container by its identifier and returns it.

 *

 * @param string $id Identifier of the entry to look for.

 *

 * @throws NotFoundExceptionInterface
No entry was found for **this** identifier.

 * @throws ContainerExceptionInterface Error while retrieving the entry.

 *

 * @return mixed Entry.

 */

public function get($id);

/**

 * Returns true if the container can return an entry for the given identifier.

 * Returns false otherwise.

 *

 * `has($id)` returning true does not mean that `get($id)` will not throw an exception.

 * It does however mean that `get($id)` will not throw a `NotFoundExceptionInterface`.

 *

 * @param string $id Identifier of the entry to look for.

 *

 * @return bool

 */

public function has($id);}

实现示例

我们先来实现接口中要求的两个方法

abstract class AbstractContainer implements ContainerInterface{

protected $resolvedEntries = [];

/**

 * @var array

 */

protected $definitions = [];

public function __construct($definitions = [])

{



foreach ($definitions as $id => $definition) {





$this->injection($id, $definition);



}

}

public function get($id)

{



if (!$this->has($id)) {





throw new NotFoundException("No entry or class found for {$id}");



}



$instance = $this->make($id);



return $instance;

}

public function has($id)

{



return isset($this->definitions[$id]);

}

实际我们容器中注入的对象是多种多样的,所以我们单独抽出实例化方法。


protected function make($name)

{



if (isset($this->resolvedEntries[$name])) {





return $this->resolvedEntries[$name];



}



$definition = $this->definitions[$name];



$params = [];



if (is_array($definition) && isset($definition['class'])) {





$params = $definition;





$definition = $definition['class'];





unset($params['class']);



}



$object = $this->reflector($definition, $params);



return $this->resolvedEntries[$name] = $object;

}

public function reflector($concrete, array $params = [])

{



if ($concrete instanceof Closure) {





return $concrete($params);



} elseif (is_string($concrete)) {





$reflection = new ReflectionClass($concrete);





$dependencies = $this->getDependencies($reflection);





foreach ($params as $index => $value) {







$dependencies[$index] = $value;





}





return $reflection->newInstanceArgs($dependencies);



} elseif (is_object($concrete)) {





return $concrete;



}

}

/**

 * @param ReflectionClass $reflection

 * @return array

 */

private function getDependencies($reflection)

{



$dependencies = [];



$constructor = $reflection->getConstructor();



if ($constructor !== null) {





$parameters = $constructor->getParameters();





$dependencies = $this->getParametersByDependencies($parameters);



}



return $dependencies;

}

/**

 *

 * 获取构造类相关参数的依赖

 * @param array $dependencies

 * @return array $parameters

 * */

private function getParametersByDependencies(array $dependencies)

{



$parameters = [];



foreach ($dependencies as $param) {





if ($param->getClass()) {







$paramName = $param->getClass()->name;







$paramObject = $this->reflector($paramName);







$parameters[] = $paramObject;





} elseif ($param->isArray()) {







if ($param->isDefaultValueAvailable()) {









$parameters[] = $param->getDefaultValue();







} else {









$parameters[] = [];







}





} elseif ($param->isCallable()) {







if ($param->isDefaultValueAvailable()) {









$parameters[] = $param->getDefaultValue();







} else {









$parameters[] = function ($arg) {









};







}





} else {







if ($param->isDefaultValueAvailable()) {









$parameters[] = $param->getDefaultValue();







} else {









if ($param->allowsNull()) {











$parameters[] = null;









} else {











$parameters[] = false;









}







}





}



}



return $parameters;

}

如你所见,到目前为止我们只实现了从容器中取出实例,从哪里去提供实例定义呢,所以我们还需要提供一个方法.


/**

 * @param string $id

 * @param string | array | callable $concrete

 * @throws ContainerException

 */

public function injection($id, $concrete)

{



if (!is_string($id)) {





throw new InvalidArgumentException(sprintf(







'The id parameter must be of type string, %s given',







is_object($id) ? get_class($id) : gettype($id)





));



}



if (is_array($concrete) && !isset($concrete['class'])) {





throw new ContainerException('数组必须包含类定义');



}



$this->definitions[$id] = $concrete;

}

只有这样吗?对的,有了这些操作我们已经有一个完整的容器了,插箱即用。

不过为了使用方便,我们可以再提供一些便捷的方法,比如数组式访问。

class Container extends AbstractContainer implements ArrayAccess{

public function offsetExists($offset)

{



return $this->has($offset);

}

public function offsetGet($offset)

{



return $this->get($offset);

}

public function offsetSet($offset, $value)

{



return $this->injection($offset, $value);

}

public function offsetUnset($offset)

{



unset($this->resolvedEntries[$offset]);



unset($this->definitions[$offset]);

}}

这样我们就拥有了一个功能丰富,使用方便的轻量级容器了,赶快整合到你的项目中去吧。

点击这里查看完整代码

以上就是php如何实现一个轻量级容器(代码示例)的详细内容,更多请关注Gxl网其它相关文章!

内容总结

以上是为您收集整理的php如何实现一个轻量级容器(代码示例)全部内容,希望文章能够帮你解决php如何实现一个轻量级容器(代码示例)所遇到的程序开发问题。 如果觉得技术教程内容还不错,欢迎将网站推荐给程序员好友。

内容备注

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。


本文关键词:

联系我们

在线咨询:点击这里给我发消息

邮件:w420220301@qq.com