PHP的容器Container如何保证唯一?
前提:
我在试着实现一个Psr容器,有get
、set
、has
、make
等方法,set
就直接保存对象,get
就判断存在则调用make
,make
根据对象是闭包还是实例依此反射函数或类,如果类的构造函数或闭包所需的函数列表里存在类,则继续调用make
方法去获得实例。
例子1
class Foobar
{
public function __construct(Container $ci)
{
echo "所需参数是具体的容器对象";
}
}
例子2
class Foobar
{
public function __construct(\Psr\Container\ContainerInterface $ci)
{
echo "所需参数是需实现了Psr容器接口的对象";
}
}
一般容器的调用方式
$contaienr->make(Foobar::class);
// 不考虑下面这个方式
//$contaienr->make(Foobar::class, $container);
问题来了,如何在调用时不将$container实例传过去,却能保证容器对象始终是唯一的呢?
下面是我具体的容器代码,经测试一般的调用没什么问题,只是如果对象需要保证是唯一的单例,我就不知道该如何处理比较好。
<?php
declare(strict_types = 1);
namespace Hello;
use ReflectionClass;
use ReflectionFunction;
use ReflectionFunctionAbstract;
use Psr\Container\ContainerInterface;
use Hello\Exception\Exception;
use Hello\Exception\NotFoundException;
class Container implements ContainerInterface
{
/**
* 资源对象
*/
private $resource = [];
/**
* 获取对象
*/
public function get($id)
{
if ($this->has($id)) {
return $this->make($id);
} else {
throw new NotFoundException("{$id} 没有找到!");
}
}
/**
* 设置对象
*/
public function set($id, $object)
{
$this->resource[$id] = $object;
}
/**
* 判断对象是否存在
*/
public function has($id)
{
return array_key_exists($id, $this->resource);
}
/**
* 删除对象
*/
public function remove($id)
{
if ($this->has($id)) {
unset($this->resource[$id]);
} else {
throw new NotFoundException("{$id} 没有找到!");
}
}
/**
* 创造对象
*/
public function make($id, $userParams = [])
{
// 已经存在
if (isset($this->resource[$id])) {
return $this->resource[$id];
}
// 判断对象
if (is_callable($id)) {
// 函数
return $this->call($id, $userParams);
} else if (is_string($id) && class_exists($id)) {
// 类名
return $this->instance($id, $userParams);
} else {
// 其他
return $id;
}
}
/**
* 参数
*/
public function parameters($object, $userParams = [])
{
// 反射函数
$func = $object instanceof ReflectionFunctionAbstract ? $object : new ReflectionFunction($object);
// 参数处理
$userParams = is_array($userParams) ? $userParams : [$userParams];
// 函数名称
$funName = $func->getName();
// 函数所需参数
$funParams = $func->getParameters();
if (empty($funParams)) {
return $userParams;
}
// 循环所需参数
$args = [];
foreach ($funParams as $key => $item) {
$class = $item->getClass();
$name = $item->getName();
if (!empty($class)) {
// 参数是对象,去实例化注入
$args[] = $this->instance($class);
}
}
return array_merge($args, $userParams);
}
/**
* 实例
*/
public function instance($class, $userParams = [])
{
// 反射类
$ins = $class instanceof ReflectionClass ? $class : new ReflectionClass($class);
// 是否可实例化
if (!$ins->isInstantiable()) {
throw new \Exception("{$ins->getName()} 无法实例化!");
}
// 构造函数
$construct = $ins->getConstructor();
// 解析参数
$params = empty($construct) ? [] : $this->parameters($construct, $userParams);
// 返回实例
return $ins->newInstanceArgs($params);
}
/**
* 函数
*/
public function call($func, $params = [])
{
// 获取参数
$params = $this->parameters($func, $params);
return $func(...$params);
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
抱歉,需求理解错误。
目前的理解是,你有些对象需要单例,有些对象需要实例?
$this
了解下