对 hyperf 的 container 和 AOP 的理解

Container

基本思路和 这篇文章:《Laravel 服务容器实例教程 —— 深入理解控制反转(IoC)和依赖注入(DI) 》 是一致的, 再结合 hyperf 文档: https://hyperf.wiki/2.0/#/zh-cn/di 理解即可。

首先依赖注入就是为了降低耦合, 所以比如你需要一个 UserService , 本来定义了类 UserService , 那么直接调用就好了。 但是万一哪天想用的是 UserPlanBService
于是你要改所有 new UserService的地方, 很麻烦,也就是紧耦合了
即使你通过类的构造函数 或者 注解 @inject 的地方,但是也要去比较多的地方修改,而且还不一定是哪个文件引用了

先说结论是: hyperf 做到了你只需要修改 config/autoload/dependencies.php 这个文件就能实现调用不同的 UserService。


return [
\App\Service\UserServiceInterface::class => \App\Service\UserService::class];

再次细说:
你希望能够把 UserService 解耦, 但是业务上比如需要 UserService 的 getInfoById() 这个接口,那么无论你怎么更换 UserPlanNService ,都必须实现这个接口,否则程序就运行不下去了。
因此定义一个 Interface 就呼之欲出了。 那么以后你只要注入 这个 interface , 而且 dependence 指定了具体实现在哪 ,所以也就做到了 解耦。

继续深入,上述虽然解耦了 但是不够灵活,不能处理更复杂的情况,比如 UserService 在实例化的时候需要判断配置文件是否开启了缓存(构造函数初始化可以更加的灵活)那么实现思路自然是工厂类,即在 UserService 上再加一层
代码示例:


namespace App\Service;

use Hyperf\Contract\ConfigInterface;use Psr\Container\ContainerInterface;

class UserServiceFactory{
// 实现一个 __invoke() 方法来完成对象的生产,方法参数会自动注入一个当前的容器实例
public function __invoke(ContainerInterface $container)
{
$config = $container->get(ConfigInterface::class);
// 我们假设对应的配置的 key 为 cache.enable
$enableCache = $config->get('cache.enable', false);
// make(string $name, array $parameters = []) 方法等同于 new ,使用 make() 方法是为了允许 AOP 的介入,而直接 new 会导致 AOP 无法正常介入流程
return make(UserService::class, compact('enableCache'));
}}

namespace App\Service;

class UserService implements UserServiceInterface{

/**
* @var bool
*/
private $enableCache;

public function __construct(bool $enableCache)
{
// 接收值并储存于类属性中
$this->enableCache = $enableCache;
}

public function getInfoById(int $id)
{
return (new Info())->fill($id);
}}

那么绑定关系就是绑定工厂类了


return [
\App\Service\UserServiceInterface::class => \App\Service\UserServiceFactory::class];

上述这些也就是 hyperf 的 container 做的事情,如果你直接调用 new UserService 肯定是不行的。

AOP - 面向切面编程

用通俗的话来讲,就是在 Hyperf 里可以通过 切面(Aspect) 介入到任意类的任意方法的执行流程中去,从而改变或加强原方法的功能,这就是 AOP。

大致可以参考 hyperf/cache 提供的使用 AOP 的方法 , 代码:vendor/hyperf/cache/src/Aspect/CacheableAspect.php
大致应该就是 缓存切入注解

public $annotations = [
    Cacheable::class,
];

发现有 Cacheable::class 这个注解的,(也就是 @Cacheable()) 则切入

// 获取类相关信息
$className = $proceedingJoinPoint->className;
$method = $proceedingJoinPoint->methodName;
$arguments = $proceedingJoinPoint->arguments['keys'];

// 获取 缓存的 key , ttl 等
[$key, $ttl, $group, $annotation] = $this->annotationManager->getCacheableValue($className, $method, $arguments);
// 获取使用的 缓存驱动
$driver = $this->manager->getDriver($group);
// 查找缓存,命中直接返回,未命中则继续执行原有函数
[$has, $result] = $driver->fetch($key);
if ($has) {
    return $result;
}
// 执行原有函数
$result = $proceedingJoinPoint->process();
// 根据之前获取的 key ttl 等设置缓存 
$driver->set($key, $result, $ttl);
if ($driver instanceof KeyCollectorInterface && $annotation instanceof Cacheable && $annotation->collect) {
    $driver->addKey($annotation->prefix . 'MEMBERS', $key);
}

return $result;

你可能感兴趣的:(php,hyperf,hyperf,依赖注入)