• Swoole实战之手撸HttpServer框架 6 简单模拟实现bean的自动加载功能 (主要就是注解Annotations与反射)


    视频地址 https://www.bilibili.com/video/BV14E411t7T4?p=8

    原理就是给类加一个Bean的注释,这个类就可以用 ClassFactory::getBean获取配置好的实例

    1 \anntest\app\core\ClassFactory.php

    <?php
    /**
     * 类的加载器
     */
    
    namespace App\core;
    
    
    use App\annotations\Bean;
    use Doctrine\Common\Annotations\AnnotationReader;
    
    class ClassFactory
    {
        private static $bean =[];
        public static function ScanBeans(string $path,string $nameSpace)
        {
           $phpfiles = glob($path."/*.php");
           //var_dump($phpfiles);
            /*array(2) {
                    [0]=>
              string(33) "/pro/anntest/app/test/MyRedis.php"
                    [1]=>
              string(32) "/pro/anntest/app/test/MyUser.php"
            }*/
            foreach ($phpfiles as $phpfile){
                require ($phpfile);
                //get_declared_classes,返回由已定义类的名字所组成数组。
                $classes = get_declared_classes();
                $reader = new AnnotationReader();
                //根据namespace过滤class
                foreach ($classes as $class){
                    if (strstr($class,$nameSpace)){
                        $refClass = new \ReflectionClass($class);
                       /* var_dump($refClass);exit*/;
                        //获取指定注释类型的注释
                        //getClassAnnotations 记得加s
                        $annos = $reader->getClassAnnotations($refClass);
                        foreach ($annos as $anno){
                            //instanceof 用于确定一个 PHP 变量是否属于某一类 class 的实例:
                            if ($anno instanceof Bean){
                                self::$bean[$refClass->getName()] = self::loadClass($refClass->getName(),$refClass->newInstance());
                            }
                        }
                        
                    }
                }
                
            }
    
        }
        public static function getBean(string $beanName)
        {
           if(isset(self::$bean[$beanName]))
               return self::$bean[$beanName];
           return false ;
        }
        
        /**
         * @param      $className
         * @param bool $object
         *
         * @return bool|object
         * @throws \Doctrine\Common\Annotations\AnnotationException
         * @throws \ReflectionException
         */
         public static function loadClass($className,$object=false)
         {
             $refClass = new \ReflectionClass($className);
             //return $refClass->newInstance();
             //获取所有的属性集合getClassAnnotation
             $properties = $refClass->getProperties();
             foreach ($properties as $property){
                 $read = new AnnotationReader();
                 $annos = $read->getPropertyAnnotations($property);
                 foreach ($annos as $anno){
                     //var_dump($anno);
                     $getValue =  $anno->do();
                     //实例化
                     //$obj  =  $refClass->newInstance();
                     $obj = $object ? $object : $refClass->newInstance();
                     //给属性赋值
                     $property->setValue($obj,$getValue);
                     return $obj;
                 }
             }
             //return false;
             return $object ? $object : $refClass->newInstance();
         }
    }
    View Code

    2 anntest\app\annotations\Bean.php

     必须加上这两行注释

    /**
    * @Annotation
    * @Target({"CLASS"})
    */


    <?php
    
    //类注释 Bean只能打在类上    用于类的自动加载
    namespace App\annotations;
    
    /**
     * @Annotation
     * @Target({"CLASS"})
     */
    class Bean
    {
        
    }
    View Code

    3 anntest\app\test\MyRedis.php

    3.1 使用Bean的命名空间

    use App\annotations\Bean;

    3.2 在类上加注释

    /**
    * @Bean()
    */
    <?php
    /**
     * Created by PhpStorm.
     * User: SUN
     * Date: 2021/12/2
     * Time: 22:48
     */
    
    namespace App\test;
    use App\annotations\Value;
    use App\annotations\Bean;
    
    /**
     * @Bean()
     */
    class MyRedis
    { 
        /**
         * @Value(name="url")
         */
         public $conn_url;
    
         
    }
    View Code

    4 anntest\app\test\MyUser.php

    再来一个类测试

    <?php
    
    namespace App\test;
    use App\annotations\Bean;
    /**
     * @Bean()
     */
    class MyUser
    {
        
    }

    5 anntest\index.php 使用

    <?php
    require_once __DIR__.'/vendor/autoload.php';
    
    use \Doctrine\Common\Annotations\AnnotationRegistry;
    use \App\test\MyRedis;
    use \App\core\ClassFactory;
    
    
    //注册注释
    AnnotationRegistry::registerLoader('class_exists'); //回调需返回true
    
    ClassFactory::ScanBeans(__DIR__.'/app/test','App\\test');
    $myRedis = ClassFactory::getBean(MyRedis::class);
    var_dump($myRedis);
     

     

  • 相关阅读:
    MySQL Online DDL导致全局锁表案例分析
    .NET Core教程--给API加一个服务端缓存啦
    任务队列和异步接口的正确打开方式(.NET Core版本)
    .NET Core中使用RabbitMQ正确方式
    .NET Core单元测试之搞死开发的覆盖率统计(coverlet + ReportGenerator )
    没有执行过rm -rf /*的开发不是好运维
    dotnet core在Task中使用依赖注入的Service/EFContext
    可能是全网首个支持阿里云Elasticsearch Xapck鉴权的Skywalking
    dpdk中QSBR具体实现
    C语言二级指针底层实现
  • 原文地址:https://www.cnblogs.com/polax/p/15717835.html
Copyright © 2020-2023  润新知