美文网首页
swoft: 1.0.0 源码解读-1

swoft: 1.0.0 源码解读-1

作者: sowork | 来源:发表于2019-02-18 19:57 被阅读11次

    看源码时结合swoft源码,边看边打断点查看打印的信息,参考 https://www.jianshu.com/p/c188f73893f1 总结比较容易阅读

    启动分析

    入口脚本: /bin/swoft

    #!/usr/bin/env php
    <?php
    require_once __DIR__ . '/bootstrap.php';
    $console = new \Swoft\Console\Console();
    $console->run();
    
    • 引入bootstrap文件,实例化并运行console实例

    启动文件: /bin/bootstrap文件

    require_once dirname(__DIR__) . '/vendor/autoload.php';
    require_once dirname(__DIR__) . '/config/define.php';
    
    // init the factory of bean
    \Swoft\Bean\BeanFactory::init();
    
    /* @var \Swoft\Bootstrap\Boots\Bootable $bootstrap*/
    $bootstrap = \Swoft\App::getBean(\Swoft\Bootstrap\Bootstrap::class);
    $bootstrap->bootstrap();
    
    • 加载composer自动加载文件autoload.php
    • 加载定义常量
    • 初始化bean工厂

    bean工厂初始化init函数: \Swoft\Bean\BeanFactory::init()

    public static function init()
        {
            $properties = self::getProperties();
            self::$container = new Container();
            self::$container->setProperties($properties);
            self::$container->autoloadServerAnnotation();
            $definition = self::getServerDefinition();
            self::$container->addDefinitions($definition);
            self::$container->initBeans();
        }
    
    • $properties = self::getProperties(); //获取项目配置
    private static function getProperties()
        {
            $properties = [];
            $config     = new Config();
            $dir        = App::getAlias('@properties');
            if (is_readable($dir)) {
                $config->load($dir);
                $properties = $config->toArray();
            }
            dd($properties); // 打印测试
            return $properties;
        }
    
    1. 加载config/properties目录下的所有配置文件并返回配置数组,$properties打印如下: properties部分配置
    • self::$container = new Container(); //实例化核心容器
    • self::$container->setProperties($properties); //将配置参数绑定到container的properties属性上
    public function setProperties(array $properties)
        {
            $this->properties = $properties;
        }
    
    • self::$container->autoloadServerAnnotation(); // 绑定扫描空间和绑定组件命名空间、解析注解
    public function autoloadServerAnnotation()
        {
            $bootScan = $this->getScanNamespaceFromProperties('bootScan');
            $resource = new ServerAnnotationResource($this->properties);
            $resource->addScanNamespace($bootScan);
            $definitions = $resource->getDefinitions();
            $this->definitions = array_merge($definitions, $this->definitions); // 将解析后的注解绑定到container的definitions属性上
        }
    
    1. $bootScan = $this->getScanNamespaceFromProperties('bootScan'); // 从配置文件中读取扫描命名空间
    private function getScanNamespaceFromProperties(string $name)
        {
            $properties = $this->properties;
            if (!isset($properties[$name]) || !\is_array($properties[$name])) {
                return [];
            }
            dd($properties[$name]); // 打印测试
            return $properties[$name];
        }
    
    bootScan的配置如下 bootScan的配置 打印信息如下: bootScan打印
    1. resource = new ServerAnnotationResource(this->properties) // 实例化注解资源
      2.1 ServerAnnotationResource构造函数 // 查看是否有自定义组件,有的话,添加到resource的customComponents数组中
      public function __construct(array $properties)
      {
          $this->properties = $properties;
          if (isset($properties['components']['custom']) && is_array($properties['components']['custom'])) {
              $this->customComponents = $properties['components']['custom'];
          }
      }
      
    2. $resource->addScanNamespace($bootScan); // 添加配置文件中指定的需要扫描的命名空间绑定到resource的scanNamespaces属性上
    public function addScanNamespace(array $namespaces)
        {
            foreach ($namespaces as $key => $namespace) {
                if (is_string($key)) {
                    $this->scanNamespaces[$key] = $namespace;
                    continue;
                }
                $nsPath = ComposerHelper::getDirByNamespace($namespace);
                if (!$nsPath) {
                    $nsPath = str_replace("\\", "/", $namespace);
                    $nsPath = BASE_PATH . "/" . $nsPath;
                }
                $this->scanNamespaces[$namespace] = $nsPath;
            }
            dd($this->scanNamespaces); // 打印调试
    
            $this->registerNamespace();
        }
    
    打印调试
    3.1 $this->registerNamespace(); // 注册命名空间
    public function registerNamespace()
        {
            $swoftDir      = dirname(__FILE__, 5); // 地址:/vendor/swoft
            $componentDirs = scandir($swoftDir); // /vendor/swoft下所有的目录
            foreach ($componentDirs as $component) {
                if ($component == '.' || $component == '..') { // 过滤./和../目录
                    continue;
                }
    
                $componentDir = $swoftDir . DS . $component; // /vendor/swoft/对应组件目录/src
                $componentCommandDir = $componentDir . DS . 'src'; ///vendor/swoft/对应组件目录
                if (! is_dir($componentCommandDir)) {
                    continue;
                }
    
                $ns = ComponentHelper::getComponentNamespace($component, $componentDir); // 获取组件命名空间
                $this->componentNamespaces[] = $ns; // 将组件命名空间绑定到resource的$componentNamespaces属性上
    
                // console component
                if ($component == $this->consoleName) { // console组件添加到容器的scanNamespaces属性上
                    $this->scanNamespaces[$ns] = $componentCommandDir;
                    continue;
                }
    
                foreach ($this->serverScan as $dir) { 
                    // 下面是swoft组件中需要扫描的目录, 如果在组件中出现下面三个任意目录,则将该组件的命名空间绑定到resource的scanNamespaces属性上
                    // $serverScan = [
                     //   'Command',
                      //   'Bootstrap',
                       //   'Aop',
                    // ];
                    $scanDir = $componentCommandDir . DS . $dir;
                    if (!is_dir($scanDir)) {
                        continue;
                    }
    
                    $scanNs                        = $ns . "\\" . $dir;
                    $this->scanNamespaces[$scanNs] = $scanDir;
                }
            }
            // 注册服务命名空间
            $this->registerServerNamespace();
        }
    

    3.2 $this->registerServerNamespace(); // 注册服务命名空间

    public function registerServerNamespace()
        {
            // 循环自定义组件,刚才实例化ServerAnnotationResource对象时,构造函数中对自定义组件进行了检测
            foreach ($this->customComponents as $ns => $componentDir) {
                if (is_int($ns)) {
                    $ns = $componentDir;
                    // 根据自定义组件的命名空间获取组件所在的目录
                    $componentDir = ComposerHelper::getDirByNamespace($ns);
                    $ns = rtrim($ns, "\\");
                    $componentDir = rtrim($componentDir, "/");
                }
    
                // 将自定义组件绑定到resource的componentNamespaces的属性上
                $this->componentNamespaces[] = $ns;
                // 根据组件命名空间获取别名
                $componentDir = alias($componentDir);
                // 将自定义组件需要扫描的目录绑定到resource的scanNamespaces属性上
                foreach ($this->serverScan as $dir) {
                    $scanDir = $componentDir . DS . $dir;
                    if (!is_dir($scanDir)) {
                        continue;
                    }
    
                    $scanNs = $ns . "\\" . $dir;
                    $this->scanNamespaces[$scanNs] = $scanDir;
                }
            }
        }
    

    3.3 alias方法介绍

    function alias(string $alias): string
        {
            return \Swoft\App::getAlias($alias);
        }
    // 如果$aliase为空或者不以@符开头的,直接返回aliase,默认self::$aliases = ['@swoft' => __DIR__,],swoft只定义了一个别名叫@swoft,但当我们传@swoft/db的时候,也可以返回db组件所在的目录绝对路径
    public static function getAlias(string $alias): string
        {
            // empty OR not an alias
            if (!$alias || $alias[0] !== '@') {
                return $alias;
            }
            if (isset(self::$aliases[$alias])) {
                return self::$aliases[$alias];
            }
            list($root) = \explode('/', $alias, 2);
            if (!isset(self::$aliases[$root])) {
                throw new \InvalidArgumentException('The set root alias does not exist,alias=' . $root);
            }
            $rootPath  = self::$aliases[$root];
            $aliasPath = \str_replace($root, '', $alias);
            return $rootPath . $aliasPath;
        }
    
    1. $definitions = $resource->getDefinitions(); // 解析需要扫描的命名空间,并将注解的信息封装成$objectDefinition对象绑定到resource的definitions属性上
    public function getDefinitions()
        {
            $classNames     = $this->registerLoaderAndScanBean();
            $fileClassNames = $this->scanFilePhpClass();// 扫描额外的文件
            $classNames     = array_merge($classNames, $fileClassNames);
            foreach ($classNames as $className) {
                $this->parseBeanAnnotations($className);
            }
            $this->parseAnnotationsData();
            return $this->definitions;
        }
    

    4.1 $classNames = $this->registerLoaderAndScanBean(); // 获取所有扫描空间下php文件

    protected function registerLoaderAndScanBean()
        {
            $phpClass = [];
            // 前面我们提到过我们将scanNamespaces和componentNamespaces绑定到resource对象上
            foreach ($this->scanNamespaces as $namespace => $dir) {
                // 此处用到了# [doctrine](https://github.com/doctrine)/**[annotations](https://github.com/doctrine/annotations)** 这个第三方扩展
    
                // 注册自动加载器回调。回调接受该类作为第一个和唯一的参数,如果找到并包含相应的文件,则必须返回true。
                AnnotationRegistry::registerLoader(function ($class) {
                    if (class_exists($class) || interface_exists($class)) {
                        return true;
                    }
    
                    return false;
                });
                $scanClass = $this->scanPhpFile($dir, $namespace);
                $phpClass  = array_merge($phpClass, $scanClass);
            }
    
            return array_unique($phpClass);
        }
    

    4.1.1 $scanClass = $this->scanPhpFile($dir, $namespace); //获取该目录下所有的php文件

    protected function scanPhpFile(string $dir, string $namespace)
        {
            if (!is_dir($dir)) {
                return [];
            }
            // 获取dir下目录和文件的一个迭代对象 参考:http://php.net/manual/zh/class.recursivedirectoryiterator.php
            $iterator = new \RecursiveDirectoryIterator($dir);
            // 递归获取该迭代对象下所有的文件和目录
            $files    = new \RecursiveIteratorIterator($iterator);
    
            $phpFiles = [];
            foreach ($files as $file) {
                // 获取文件类型
                $fileType = pathinfo($file, PATHINFO_EXTENSION);
                if ($fileType != 'php') {
                    continue;
                }
    
                $replaces = ['', '\\', '', ''];
                $searches = [$dir, '/', '.php', '.PHP'];
    
                // 将真实的文件地址按照对应参数进行的进行替换
                // 比如:/var/www/swoft/vendor/composer/../../app/Boot/SwoftListener.php 替换完成后会变成 \SwoftListener
                $file       = str_replace($searches, $replaces, $file);
                $phpFiles[] = $namespace . $file;
            }
    
            return $phpFiles;
        }
    

    4.2 $fileClassNames = $this->scanFilePhpClass(); // 获取默认的需要扫描的php文件

    protected function scanFilePhpClass()
        {
            $phpClass = [];
            // 此时resource上的scanFiles默认是空的
            foreach ($this->scanFiles as $ns => $files) {
                foreach ($files as $file) {
                    $pathInfo = pathinfo($file);
                    if (!isset($pathInfo['filename'])) {
                        continue;
                    }
                    $phpClass[] = $ns . "\\" . $pathInfo['filename'];
                }
            }
    
            return $phpClass;
        }
    

    4.3 $this->parseBeanAnnotations($className); // 解析扫描得到的php文件的注解,将相应的注解绑定到resource的annotation属性上

    public function parseBeanAnnotations(string $className)
        {
            //  判断类、接口是否存在
            if (!class_exists($className) && !interface_exists($className)) {
                return null;
            }
    
            // 注解解析器
            // 实例化一个注解解析器
            $reader           = new AnnotationReader();
            // 添加需要忽略的注解
            $reader           = $this->addIgnoredNames($reader);
            // 获取一个反射类对象实例
            $reflectionClass  = new \ReflectionClass($className);
            // 获取类所有注解
            $classAnnotations = $reader->getClassAnnotations($reflectionClass);
    
            // 没有类注解不解析其它注解
            if (empty($classAnnotations)) {
                return;
            }
    
            foreach ($classAnnotations as $classAnnotation) {
                // 绑定注解类的class属性到resource上的annotations属性上
                $this->annotations[$className]['class'][get_class($classAnnotation)] = $classAnnotation;
            }
    
            // 解析属性
            // 获取反射类的属性列表
            $properties = $reflectionClass->getProperties();
            foreach ($properties as $property) {
                if ($property->isStatic()) {
                    continue;
                }
                $propertyName        = $property->getName();
                 // 如果发现你的注解没有被获取到,可以查看是否被全局忽略,doctrine/annotations默认已经添加了很多,详见:https://github.com/doctrine/annotations/blob/master/lib/Doctrine/Annotations/AnnotationReader.php
                $propertyAnnotations = $reader->getPropertyAnnotations($property);
                foreach ($propertyAnnotations as $propertyAnnotation) {
                    // 绑定注解类的property属性到resource的annotation属性上
                    $this->annotations[$className]['property'][$propertyName][get_class($propertyAnnotation)] = $propertyAnnotation;
                }
            }
    
            // 解析方法
            $publicMethods = $reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC);
            foreach ($publicMethods as $method) {
                if ($method->isStatic()) {
                    continue;
                }
    
                $methodName = $method->getName();
    
                // 解析方法注解
                $methodAnnotations = $reader->getMethodAnnotations($method);
    
                foreach ($methodAnnotations as $methodAnnotation) {
                    // 绑定注解类的method属性到resource的annotation属性上
                    $this->annotations[$className]['method'][$methodName][get_class($methodAnnotation)][] = $methodAnnotation;
                }
            }
        }
    

    4.3.1 $reader = $this->addIgnoredNames($reader); // 添加忽略的注解

    protected function addIgnoredNames(AnnotationReader $reader)
        {
          // protected $ignoredNames
          // = [
          //    'Usage',
          //    'Options',
          //    'Arguments',
          //    'Example',
          //   ];
          // 默认reader会忽略上述注解
            foreach ($this->ignoredNames as $name) {
                $reader->addGlobalIgnoredName($name);
            }
    
            return $reader;
        }
    

    4.4 $this->parseAnnotationsData(); // 解析注解数据

    public function parseAnnotationsData()
        {
            // 对resource上绑定的注解循环进行处理
            foreach ($this->annotations as $className => $annotation) {
                $classAnnotations = $annotation['class'];
                $this->parseClassAnnotations($className, $annotation, $classAnnotations);
            }
        }
    

    4.4.1 $this->parseClassAnnotations($className, $annotation, $classAnnotations); // 解析注解,对于注解涉及到wapper、parser、collect等操作,具体含义请看后面介绍

    private function parseClassAnnotations(string $className, array $annotation, array $classAnnotations)
        {
            // 当注解依赖多个类循环处理
            foreach ($classAnnotations as $classAnnotation) {
                // 获取注解对象的类名 e.g. Swoft\Bean\Annotation\ServerListener
                $annotationClassName = get_class($classAnnotation);
                $classNameTmp        = str_replace('\\', '/', $annotationClassName);
                // 返回路径中的文件名部分 e.g. ServerListener
                $classFileName       = basename($classNameTmp);
                // 返回路径中的目录部分 e.g. Swoft/Bean
                $beanNamespaceTmp    = dirname($classNameTmp, 2);
                 // 路径转换成命名空间 e.g. Swoft/Bean
                $beanNamespace       = str_replace('/', '\\', $beanNamespaceTmp);
    
                // 获取注解包装类名称 e.g. "Swoft\Bean\Wrapper\ServerListenerWrapper"
                $annotationWrapperClassName = "{$beanNamespace}\\Wrapper\\{$classFileName}Wrapper";
    
                if (!class_exists($annotationWrapperClassName)) {
                    continue;
                }
    
                 // 作用:注解的wapper,并将resource对象传递到wapper中
                /* @var WrapperInterface $wrapper */
                $wrapper = new $annotationWrapperClassName($this);
    
                // wrapper extend
                // 遍历组件命名空间,对组件注解wapper进行扩展
                foreach ($this->componentNamespaces as $componentNamespace) {
                    $annotationWrapperExtendClassName = "{$componentNamespace}\\Bean\\Wrapper\\Extend\\{$classFileName}Extend";
                    if (!class_exists($annotationWrapperExtendClassName)) {
                        continue;
                    }
                    $extend = new $annotationWrapperExtendClassName();
                    // 将扩展的wapper绑定到wapper的extends属性上
                    $wrapper->addExtends($extend);
                }
    
                $objectDefinitionAry = $wrapper->doWrapper($className, $annotation);
                if ($objectDefinitionAry != null) {
                    list($beanName, $objectDefinition) = $objectDefinitionAry;
                    // 将解析后的注解类绑定到resource的definitions属性上
                    $this->definitions[$beanName] = $objectDefinition;
                }
            }
        }
        public function addExtends(WrapperExtendInterface $extend)
        {
            $extendClass = get_class($extend);
            $this->extends[$extendClass] = $extend;
        }    
        public function doWrapper(string $className, array $annotations)
        {
            $reflectionClass = new \ReflectionClass($className);
    
            // 解析类注解,通过注解类获取到对应的parser解析器,触发collector操作,返回关于该bean的一些状态信息,如ServerListenerParser中返回:[$beanName, $scope, '']。 $beanName 是 声明@Bean注解的类名称,$scope是返回是否是单例
            $beanDefinition = $this->parseClassAnnotations($className, $annotations['class']);
    
            // 没配置注入bean注解
            if (empty($beanDefinition) && !$reflectionClass->isInterface()) {
                // 解析属性 获取反射类的属性
                $properties = $reflectionClass->getProperties();
    
                // 解析注解属性 获取反射类所有属性属性的注解
                $propertyAnnotations = $annotations['property']??[];
                $this->parseProperties($propertyAnnotations, $properties, $className);
    
                // 解析方法
                $publicMethods = $reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC);
                $methodAnnotations = $annotations['method'] ??[];
    
                $this->parseMethods($methodAnnotations, $className, $publicMethods);
    
                return null;
            }
    
    
            // parser bean annotation
            list($beanName, $scope, $ref) = $beanDefinition;
    
            // 初始化对象 将解析的bean的数据实例化为一个ObjectDefinition对象
            $objectDefinition = new ObjectDefinition();
            $objectDefinition->setName($beanName);
            $objectDefinition->setClassName($className);
            $objectDefinition->setScope($scope);
            $objectDefinition->setRef($ref);
    
            if (!$reflectionClass->isInterface()) {
                // 解析属性
                $properties = $reflectionClass->getProperties();
    
                // 解析属性
                $propertyAnnotations = $annotations['property']??[];
                $propertyInjections = $this->parseProperties($propertyAnnotations, $properties, $className);
                // 将解析后的注解属性返回值绑定到ObjectDefinition对象的propertyInjections属性上
                $objectDefinition->setPropertyInjections($propertyInjections);
            }
    
            // 解析方法
            $publicMethods = $reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC);
            $methodAnnotations = $annotations['method'] ??[];
            $this->parseMethods($methodAnnotations, $className, $publicMethods);
    
            return [$beanName, $objectDefinition];
        }
          public function parseClassAnnotations(string $className, array $annotations)
            {
             // 判断是否能够解析类注解
            if (!$this->isParseClass($annotations)) {
                return null;
            }
    
            $beanData = null;
            foreach ($annotations as $annotation) {
                $annotationClass = get_class($annotation);
                 // 判断该注解是否是wapper中含有的注解
                if (!in_array($annotationClass, $this->getClassAnnotations())) {
                    continue;
                }
    
                // annotation parser 获取该注解类对应的注解解析器
                $annotationParser = $this->getAnnotationParser($annotation);
                if ($annotationParser == null) {
                    continue;
                }
                // 获取注解解析后的数据, 在parser的过程中,触发collect操作
                $annotationData = $annotationParser->parser($className, $annotation);
                if ($annotationData != null) {
                    $beanData = $annotationData;
                }
            }
    
            return $beanData;
        }
    
        private function isParseClass(array $annotations): bool
        {
            // 如果允许解析类注解或者允许解析
            return $this->isParseClassAnnotations($annotations) || $this->isParseExtendAnnotations($annotations, 1);
        }
        private function getClassAnnotations(): array
        {
            // protected $classAnnotations = [  ServerListener::class ]; 由具体的wapper类引入注解类
            return array_merge($this->classAnnotations, $this->getExtendAnnotations(1));
        }
        // 获取扩展的注解类
        private function getExtendAnnotations(int $type = 1): array
        {
            $annotations = [];
            foreach ($this->extends as $extend) {
                if ($type == 1) {
                    $extendAnnoation = $extend->getClassAnnotations();
                } elseif ($type == 2) {
                    $extendAnnoation = $extend->getPropertyAnnotations();
                } else {
                    $extendAnnoation = $extend->getMethodAnnotations();
                }
                $annotations = array_merge($annotations, $extendAnnoation);
            }
    
            return $annotations;
        }
        private function getAnnotationParser($objectAnnotation)
        {
            $annotationClassName = get_class($objectAnnotation);
            $classNameTmp = str_replace('\\', '/', $annotationClassName);
            $className = basename($classNameTmp);
            $namespaceDir = dirname($classNameTmp, 2);
            $namespace = str_replace('/', '\\', $namespaceDir);
    
            // 解析器类名 根据注解类获取到的命名空间+固定的命名空间+类名称获取注解解析器名称
            $annotationParserClassName = "{$namespace}\\Parser\\{$className}Parser";
            if (!class_exists($annotationParserClassName)) {
                return null;
            }
    
            $annotationParser = new $annotationParserClassName($this->annotationResource);
            return $annotationParser;
        }
        // 解析类属性
        private function parseProperties(array $propertyAnnotations, array $properties, string $className)
        {
            $propertyInjections = [];
    
            /* @var \ReflectionProperty $property */
            foreach ($properties as $property) {
                if ($property->isStatic()) {
                    continue;
                }
                $propertyName = $property->getName();
                if (!isset($propertyAnnotations[$propertyName]) || !$this->isParseProperty($propertyAnnotations[$propertyName])) {
                    continue;
                }
    
                 // 通过反射类获取该属性的值
                $object = new $className();
                $property->setAccessible(true);
                $propertyValue = $property->getValue($object);
    
                list($injectProperty, $isRef) = $this->parsePropertyAnnotations($propertyAnnotations, $className, $propertyName, $propertyValue);
                if ($injectProperty == null) {
                    continue;
                }
    
                $propertyInjection = new PropertyInjection($propertyName, $injectProperty, (bool)$isRef);
                $propertyInjections[$propertyName] = $propertyInjection;
            }
    
            return $propertyInjections;
        }
        private function parsePropertyAnnotations(array $propertyAnnotations, string $className, string $propertyName, $propertyValue)
        {
            $isRef = false;
            $injectProperty = "";
    
            // 没有任何注解
            if (empty($propertyAnnotations) || !isset($propertyAnnotations[$propertyName])
                || !$this->isParseProperty($propertyAnnotations[$propertyName])
            ) {
                return [null, false];
            }
    
            // 属性注解解析
            foreach ($propertyAnnotations[$propertyName] as $propertyAnnotation) {
                $annotationClass = get_class($propertyAnnotation);
                // 判断属性注解是否属于定义的注解
                if (!in_array($annotationClass, $this->getPropertyAnnotations())) {
                    continue;
                }
    
                // 解析器 【使用具体的解析器(如ValueParser,ReferenceParser等)解析注入元信息】
                $annotationParser = $this->getAnnotationParser($propertyAnnotation);
                if ($annotationParser === null) {
                    $injectProperty = null;
                    $isRef = false;
                    continue;
                }
                // 返回注入的属性值$injectProperty和isRef,isRef 决定属性需要注入一个Bean还是一个基本类型值
                list($injectProperty, $isRef) = $annotationParser->parser($className, $propertyAnnotation, $propertyName, "", $propertyValue);
            }
    
            return [$injectProperty, $isRef];
        }
        public function setPropertyInjections($propertyInjections)
        {
            $this->propertyInjections = $propertyInjections;
        }
        private function parseMethods(array $methodAnnotations, string $className, array $publicMethods)
        {
            // 循环解析
            foreach ($publicMethods as $method) {
                /* @var \ReflectionMethod $method*/
                if ($method->isStatic()) {
                    continue;
                }
    
                /* @var \ReflectionClass $declaredClass*/
                $declaredClass = $method->getDeclaringClass();
                $declaredName = $declaredClass->getName();
    
                // 不是当前类方法
                if ($declaredName != $className) {
                    continue;
                }
                $this->parseMethodAnnotations($className, $method, $methodAnnotations);
            }
        }
         private function parseMethodAnnotations(string $className, \ReflectionMethod $method, array $methodAnnotations)
        {
            // 方法没有注解解析
            $methodName = $method->getName();
            $isWithoutMethodAnnotation = empty($methodAnnotations) || !isset($methodAnnotations[$methodName]);
            if ($isWithoutMethodAnnotation || !$this->isParseMethod($methodAnnotations[$methodName])) {
                $this->parseMethodWithoutAnnotation($className, $methodName);
                return;
            }
    
            // 循环方法注解解析
            foreach ($methodAnnotations[$methodName] as $methodAnnotationAry) {
                foreach ($methodAnnotationAry as $methodAnnotation) {
                    if (!$this->inMethodAnnotations($methodAnnotation)) {
                        continue;
                    }
    
                    // 解析器解析
                    $annotationParser = $this->getAnnotationParser($methodAnnotation);
                    if ($annotationParser == null) {
                        $this->parseMethodWithoutAnnotation($className, $methodName);
                        continue;
                    }
                    // 同类注解一致
                    $annotationParser->parser($className, $methodAnnotation, "", $methodName);
                }
            }
        }
        private function parseMethodWithoutAnnotation(string $className, string $methodName)
        {
            // 该解析器默认不管方法有没有注解都对所有swoft组件的collector进行了收集,这块在swoft1.0比较绕,swoft2.0会重写该逻辑,只针对有注解的进行搜集
            $parser = new MethodWithoutAnnotationParser($this->annotationResource);
            $parser->parser($className, null, "", $methodName);
        }
        public function parser(string $className, $objectAnnotation = null, string $propertyName = "", string $methodName = "", $propertyValue = null)
        {
            $swoftDir      = dirname(__FILE__, 5);
            $componentDirs = scandir($swoftDir);
            foreach ($componentDirs as $component) {
                if ($component == '.' || $component == '..') {
                    continue;
                }
    
                $componentCommandDir = $swoftDir . DS . $component . DS . 'src/Bean/Collector';
                if (!is_dir($componentCommandDir)) {
                    continue;
                }
    
                $componentNs = ComponentHelper::getComponentNs($component);
                $collectNs = "Swoft{$componentNs}\\Bean\\Collector";
                $collectorFiles = scandir($componentCommandDir);
                foreach ($collectorFiles as $collectorFile){
                    $pathInfo = pathinfo($collectorFile);
                    if(!isset($pathInfo['filename'])){
                        continue;
                    }
                    $fileName = $pathInfo['filename'];
                    $collectClassName = $collectNs.'\\'.$fileName;
                    if(!class_exists($collectClassName)){
                        continue;
                    }
    
                    /* @var \Swoft\Bean\CollectorInterface $collector */
                    $collector = new $collectClassName();
                    $collector->collect($className, $objectAnnotation, $propertyName, $methodName, $propertyValue);
                }
            }
    
            return null;
        }
    
    • $definition = self::getServerDefinition(); // 获取类型为server 的bean对象,返回该bean对象的定义 如:return [ 'commandRoute' => [ 'class' =>HandlerMapping::class,]];
    private static function getServerDefinition(): array
        {
            // 获取@console别名的路径
            $file             = App::getAlias('@console');
            $configDefinition = [];
            if (\is_readable($file)) {
                $configDefinition = require_once $file; // 获取/swoft/config/beans/console.php配置文件内容
            }
            // BootBeanCollector::TYPE_SERVER = 'server'
            // 获取核心bean
            $coreBeans  = self::getCoreBean(BootBeanCollector::TYPE_SERVER);
            return ArrayHelper::merge($coreBeans, $configDefinition);
        }
        private static function getCoreBean(string $type): array
        {
            $collector = BootBeanCollector::getCollector(); // 获取启动时的collector的beans数组,使用了@BootBean注解的bean,存放到该bootBeanCollector的beans数组中
            // dd($collector); 详见图5-1
            if (!isset($collector[$type])) {
                return [];
            }
    
            $coreBeans = [];
            /** @var array $bootBeans */
            $bootBeans = $collector[$type];
            foreach ($bootBeans as $beanName) {
                /* @var \Swoft\Core\BootBeanInterface $bootBean */
                $bootBean  = App::getBean($beanName);  // 获取默认启动的bean对象,启动过程中根据是否是单例对象会被绑定到container的singletonEntries属性上
                $beans     = $bootBean->beans();
                $coreBeans = ArrayHelper::merge($coreBeans, $beans);
            }
    
            return $coreBeans;
        }
        // APP::getBean()
        public static function getBean(string $name)
        {
            return ApplicationContext::getBean($name);
        }
        // ApplicationContext::getBean()
        public static function getBean(string $name)
        {
            return BeanFactory::getBean($name);
        }
        // BeanFactory::getBean()
        public static function getBean(string $name)
        {
            return self::$container->get($name);
        }
        public function get(string $name)
        {
            // 如果单例实体singletonEntries中已经存在该bean,那么直接返回该对象
            if (isset($this->singletonEntries[$name])) {
                return $this->singletonEntries[$name];
            }
    
            // 未定义
            if (!isset($this->definitions[$name])) {
                throw new \InvalidArgumentException(sprintf('Bean %s not exist', $name));
            }
    
            /* @var ObjectDefinition $objectDefinition */
            $objectDefinition = $this->definitions[$name]; // 前面在autoloadServerAnnotation方法将resource上的definitions属性绑定到了container的definitions属性上
    
            return $this->set($name, $objectDefinition);
        }
        private function set(string $name, ObjectDefinition $objectDefinition)
        {
            // bean创建信息
            $scope             = $objectDefinition->getScope();  // 获取scope值
            $className         = $objectDefinition->getClassName(); // 获取类名
            $propertyInjects   = $objectDefinition->getPropertyInjections(); // 获取注入的属性
            $constructorInject = $objectDefinition->getConstructorInjection(); // 获取注入的构造属性
    
            if ($refBeanName = $objectDefinition->getRef()) { // 判断是否有引用,根据refBeanName寻找到最终实现类【ref属性重定向依赖查找,一般用于在Interface这种需要具体实现类的Bean上,用于指定实际使用的实现类】
                return $this->get($refBeanName);
            }
    
            // 构造函数
            // 构造器注入的逻辑看了代码没有具体代码有调用过setConstructorInjection方法,swoft应该没有实现构造器注入的逻辑
            $constructorParameters = [];
            if ($constructorInject !== null) {
                $constructorParameters = $this->injectConstructor($constructorInject);
            }
    
            $reflectionClass = new \ReflectionClass($className);
            $properties      = $reflectionClass->getProperties();
    
            // new实例 $this->initMethod = ‘init’
            $isExeMethod = $reflectionClass->hasMethod($this->initMethod);
            // 生成一个实例对象
            $object      = $this->newBeanInstance($reflectionClass, $constructorParameters);
    
            // 属性注入
            $this->injectProperties($object, $properties, $propertyInjects);
    
            // 执行初始化方法
            if ($isExeMethod) {
                $object->{$this->initMethod}();
            }
    
            if (!$object instanceof AopInterface) {
                $object = $this->proxyBean($name, $className, $object); // 生成一个代理对象,通过完全clone一个类的代码重新实例一个新的对象
            }
    
            // 单例处理
            if ($scope === Scope::SINGLETON) {
                $this->singletonEntries[$name] = $object;
            }
    
            return $object;
        }
        private function injectConstructor(MethodInjection $constructorInject): array
        {
            $constructorParameters = [];
    
            /* @var ArgsInjection $parameter */
            foreach ($constructorInject->getParameters() as $parameter) {
                $argValue = $parameter->getValue(); 
                if (\is_array($argValue)) {// 对于注入的数组值要根据ref区分是否是引用类型或基本类型值
                    $constructorParameters[] = $this->injectArrayArgs($argValue);
                    continue;
                }
                if ($parameter->isRef()) {
                    $constructorParameters[] = $this->get($parameter->getValue());
                    continue;
                }
                $constructorParameters[] = $parameter->getValue();
            }
    
            return $constructorParameters;
        }
        private function newBeanInstance(\ReflectionClass $reflectionClass, array $constructorParameters)
        {
            if ($reflectionClass->hasMethod('__construct')) {
                return $reflectionClass->newInstanceArgs($constructorParameters);
            }
    
            return $reflectionClass->newInstance();
        }
        private function injectProperties($object, array $properties, $propertyInjects)
        {
            foreach ($properties as $property) {
                if ($property->isStatic()) {
                    continue;
                }
    
                $propertyName = $property->getName();
                if (!isset($propertyInjects[$propertyName])) {
                    continue;
                }
    
                // 设置可用
                if (!$property->isPublic()) {
                    $property->setAccessible(true);
                }
    
                /* @var PropertyInjection $propertyInject */
                $propertyInject = $propertyInjects[$propertyName];
                $injectProperty = $propertyInject->getValue(); // 获取注入的值
    
                // 属性是数组 循环数组里面的值,分析值类型是引用类型还是基本类型
                if (\is_array($injectProperty)) {
                    $injectProperty = $this->injectArrayArgs($injectProperty);
                }
    
                // 属性是bean引用【或者说是一个引用bean对象】
                if ($propertyInject->isRef()) {
                    $injectProperty = $this->get($injectProperty);
                }
    
                if ($injectProperty !== null) { // 如果不为null,直接注入该值
                    $property->setValue($object, $injectProperty);
                }
            }
        }
        private function injectArrayArgs(array $injectProperty): array
        {
            $injectAry = [];
            foreach ($injectProperty as $key => $property) {
                // 递归循环注入
                if (\is_array($property)) {
                    $injectAry[$key] = $this->injectArrayArgs($property);
                    continue;
                }
    
                // 参数注入
                if ($property instanceof ArgsInjection) {
                    $propertyValue = $property->getValue();
                    if ($property->isRef()) {
                        $injectAry[$key] = $this->get($propertyValue);
                        continue;
                    }
                    $injectAry[$key] = $propertyValue;
                }
            }
    
            if (empty($injectAry)) {
                $injectAry = $injectProperty;
            }
    
            return $injectAry;
        }
        private function proxyBean(string $name, string $className, $object)
        {
            /* @var Aop $aop */
            $aop = App::getBean(Aop::class); // 获取aop bean对象
    
            $rc  = new \ReflectionClass($className);
            $rms = $rc->getMethods();
            foreach ($rms as $rm) {
                $method      = $rm->getName();
                $annotations = Collector::$methodAnnotations[$className][$method] ?? []; // 获取方法注解
                $annotations = array_unique($annotations);
                $aop->match($name, $className, $method, $annotations); // 
            }
    
            $handler = new AopHandler($object);
    
            return Proxy::newProxyInstance(\get_class($object), $handler);
        }
        public function match(string $beanName, string $class, string $method, array $annotations)
        {
            foreach ($this->aspects as $aspectClass => $aspect) {
                if (!isset($aspect['point'], $aspect['advice'])) {
                    continue;
                }
    
                // Include
                $pointBeanInclude = $aspect['point']['bean']['include'] ?? [];
                $pointAnnotationInclude = $aspect['point']['annotation']['include'] ?? [];
                $pointExecutionInclude = $aspect['point']['execution']['include'] ?? [];
    
                // Exclude
                $pointBeanExclude = $aspect['point']['bean']['exclude'] ?? [];
                $pointAnnotationExclude = $aspect['point']['annotation']['exclude'] ?? [];
                $pointExecutionExclude = $aspect['point']['execution']['exclude'] ?? [];
    
                $includeMath = $this->matchBeanAndAnnotation([$beanName], $pointBeanInclude) || $this->matchBeanAndAnnotation($annotations, $pointAnnotationInclude) || $this->matchExecution($class, $method, $pointExecutionInclude);
    
                $excludeMath = $this->matchBeanAndAnnotation([$beanName], $pointBeanExclude) || $this->matchBeanAndAnnotation($annotations, $pointAnnotationExclude) || $this->matchExecution($class, $method, $pointExecutionExclude);
    
                if ($includeMath && ! $excludeMath) {
                    $this->map[$class][$method][] = $aspect['advice'];
                }
            }
        }
        public static function newProxyInstance(string $className, HandlerInterface $handler)
        {
            $reflectionClass = new \ReflectionClass($className);
            $reflectionMethods = $reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC | \ReflectionMethod::IS_PROTECTED);
    
            // Proxy property
            $id = \uniqid('', false);
            $proxyClassName = \basename(str_replace("\\", '/', $className)); // 返回文件名
            $proxyClassName = $proxyClassName . '_' . $id;
            $handlerPropertyName = '__handler_' . $id;
    
            // Base class template
            $template = "class $proxyClassName extends $className {
                private \$$handlerPropertyName;
                public function __construct(\$handler)
                {
                    \$this->{$handlerPropertyName} = \$handler;
                }
            ";
    
            // Methods
            $template .= self::getMethodsTemplate($reflectionMethods, $handlerPropertyName);
            $template .= '}';
    
            eval($template);
            $newRc = new \ReflectionClass($proxyClassName);
    
            return $newRc->newInstance($handler); // 返回一个新的实例对象
        }
        private static function getMethodsTemplate(array $reflectionMethods, string $handlerPropertyName): string
        {
            $template = '';
            foreach ($reflectionMethods as $reflectionMethod) {
                $methodName = $reflectionMethod->getName();
    
                // not to override method
                if ($reflectionMethod->isConstructor() || $reflectionMethod->isStatic()) {
                    continue;
                }
                
                // define override methodBody, 最终通过aop的execute进行执行
                $methodBody = "{
                    return \$this->{$handlerPropertyName}->invoke('{$methodName}', func_get_args());
                }
                ";
                
                // the template of parameter
                $template .= " public function $methodName (";
                $template .= self::getParameterTemplate($reflectionMethod);
                $template .= ' ) ';
    
                // the template of return type
                $reflectionMethodReturn = $reflectionMethod->getReturnType();
                if ($reflectionMethodReturn !== null) {
                    $returnType = $reflectionMethodReturn->__toString();
                    $returnType = $returnType === 'self' ? $reflectionMethod->getDeclaringClass()->getName() : $returnType;
                    $template .= " : $returnType";
                    // if returnType is void
                    if ($returnType === 'void') {
                        $methodBody = str_replace('return ', '', $methodBody);
                    }
                }
    
                // append methodBody
                $template .= $methodBody;
            }
    
            return $template; // 返回代理对象 执行方法的模板string
        }
        public function invoke($method, $parameters)
        {
            /* @var Aop $aop */
            $aop = \bean(Aop::class);
    
            return $aop->execute($this->target, $method, $parameters);
        }
        public function execute($target, string $method, array $params)
        {
            $class = \get_class($target);
    
            // If doesn't have any advices, then execute the origin method
            if (!isset($this->map[$class][$method]) || empty($this->map[$class][$method])) {
                return $target->$method(...$params);
            }
    
            // Apply advices's functionality
            $advices = $this->map[$class][$method];
            return $this->doAdvice($target, $method, $params, $advices);
        }
    
    图5-1

    相关文章

      网友评论

          本文标题:swoft: 1.0.0 源码解读-1

          本文链接:https://www.haomeiwen.com/subject/qlwxsqtx.html