Beispiel #1
0
 /**
  * 获取invoker信息
  *
  * @param Invoker $invoker        
  * @param $method http方法
  * @param $uri http url
  * @return array
  */
 public function getInvokerInfo($method, $uri, $invoker)
 {
     $res = array();
     $res['impl'] = $invoker->getMethodName();
     $ann = new AnnotationReader();
     $refl = new \ReflectionClass($invoker->getClassName());
     $mrefl = $refl->getMethod($invoker->getMethodName());
     $anns = $ann->getMethodAnnotations($mrefl, true);
     // 过滤无效的参数
     if (isset($anns['param'])) {
         $anns['param'] = array_values(array_filter($anns['param'], function ($i) {
             return isset($i['value']);
         }));
     }
     if (isset($anns['return'])) {
         $anns['return'] = array_values(array_filter($anns['return'], function ($i) {
             return isset($i['value']);
         }));
     }
     if (isset($anns['throws'])) {
         $anns['throws'] = array_values(array_filter($anns['throws'], function ($i) {
             return isset($i['value']);
         }));
     }
     $res['doc'] = $this->getDocText($mrefl->getDocComment());
     //找到匹配的@route注释
     foreach ($anns['route'] as $route_doc) {
         //TODO: 同时精确匹配和通配符匹配时, 怎么处理
         if (isset($route_doc['value'])) {
             list($m, $u) = $route_doc['value'];
             $full_url = $invoker->getContainer()->path . '/' . $u;
             $full_url = HttpRouterEntries::stringToPath($full_url);
             if ($full_url == HttpRouterEntries::stringToPath($uri) && $m === $method) {
                 $text = $this->getDocText($route_doc['desc']);
                 if (!empty($text)) {
                     $res['doc'] .= "\r\n";
                     $res['doc'] .= $text;
                 }
                 break;
             }
         }
     }
     $anns['route'];
     $res['root'] = '/';
     $res['path'] = $invoker->getContainer()->path;
     // 获取参数信息
     $res['params'] = array();
     foreach ($invoker->getParams()->getParams() as $param) {
         list($is_const, $value, $info, $id) = $param;
         list($name, $is_ref, $is_optional, $default) = $info;
         if (!$is_const) {
             $res['params'][$name] = array('value' => $value, 'is_ref' => $is_ref, 'is_optional' => $is_optional, 'default' => $default, 'doc' => $this->getDocText($anns['param'][$id]['desc']));
         }
     }
     // 依赖只是特殊的参数
     $defaults = $refl->getDefaultProperties();
     foreach ($refl->getProperties() as $property) {
         foreach ($ann->getPropertyAnnotations($property, true) as $type => $value) {
             if ($type !== 'inject') {
                 continue;
             }
             $name = $property->getName();
             $value = $value[0];
             if (is_array($value['value'])) {
                 $src = $value['value']['src'];
                 if (isset($value['value']['optional']) && $value['value']['optional']) {
                     $is_optional = true;
                 }
                 if (isset($value['value']['default'])) {
                     $default = $value['value']['default'];
                 }
             } else {
                 $src = $value['value'];
             }
             if (substr($src, 0, 1) !== '$') {
                 continue;
             }
             if (array_key_exists($name, $defaults)) {
                 $is_optional = true;
                 $default = $defaults[$name];
             }
             $res['params'][$name] = array('value' => $src, 'is_ref' => false, 'is_optional' => $is_optional, 'default' => $default, 'doc' => $this->getDocText($value['desc']));
         }
     }
     // 获取返回值信息
     $res['returns'] = array();
     foreach ($invoker->getReturns()->getParams() as $fun_name => $calls) {
         foreach ($calls as $id => $call) {
             $args = array();
             foreach ($call as $num => $arg) {
                 list($is_const, $value, $pos, $info) = $arg;
                 list($name, $is_ref, $is_optional, $default) = $info;
                 $args[$num] = array('value' => $value, 'name' => $name, 'is_const' => $is_const);
             }
             $res['returns'][] = array('name' => $fun_name, 'args' => $args, 'doc' => $id === -1 ? null : $this->getDocText($anns['return'][$id]['desc']));
         }
     }
     // 获取异常信息
     $res['throws'] = array();
     foreach ($invoker->getThrows()->getParams() as $exce_name => $throws) {
         // $res['throws'][$exce_name] = array();
         foreach ($throws as $fun_name => $calls) {
             foreach ($calls as $id => $call) {
                 $args = array();
                 if ($call !== null) {
                     foreach ($call as $num => $arg) {
                         $args[$num] = array('value' => $arg, 'name' => null, 'is_const' => true);
                     }
                 }
                 $res['throws'][$exce_name][] = array('name' => $fun_name, 'args' => $args, 'doc' => $this->getDocText($anns['throws'][$id]['desc']));
             }
         }
     }
     return $res;
 }
Beispiel #2
0
 /**
  * 
  * @param string $class 类名
  * @param string $method ==null时load所有方法, !==null时load指定方法
  */
 public function load($class, $method)
 {
     $this->class = $class;
     //获取方法
     $reflection = new \ReflectionClass($class);
     $reader = new AnnotationReader($reflection);
     $class_ann = $reader->getClassAnnotations($reflection);
     Verify::isTrue(isset($class_ann['path']), $class . ' @path not found');
     Verify::isTrue(count($class_ann['path']) === 1, $class . ' @path ambiguity');
     $path = $class_ann['path'][0]['value'];
     $this->path = $path;
     $specified = $method;
     foreach ($reflection->getMethods() as $method) {
         if ($specified !== null && $specified !== $method->getName()) {
             Logger::DEBUG("specified method: {$specified}, ignore {$class}::{$method->getName()}");
             continue;
         }
         $anns = $reader->getMethodAnnotations($method, false);
         if (!isset($anns['route'])) {
             Logger::DEBUG("no @route, ignore {$class}::{$method->getName()}");
             continue;
         }
         //Verify::isTrue(count($anns['route']) == 1, "$class::{$method->getName()} @route repeated set");
         $invoker = $this->factory->create('phprs\\Invoker', array($this, $method));
         foreach ($anns['route'] as $ann) {
             $route = $ann['value'];
             Verify::isTrue(is_array($route) && (count($route) == 2 || count($route) == 3), "{$class}::{$method->getName()} syntax error @route, example: @route({\"GET\" ,\"/api?a=2\"}) or @route({\"GET\" ,\"/api?a=2\",true})");
             list($http_method, $uri, $strict) = $route + [null, null, null];
             $this->routes[$http_method][] = [$path . '/' . $uri, $invoker, $strict];
         }
         foreach ($anns as $type => $v) {
             if ($type == 'route') {
                 continue;
             }
             $id = 0;
             foreach ($v as $ann) {
                 if (!is_array($ann) || !isset($ann['value'])) {
                     continue;
                 }
                 $invoker->bind($id++, $type, $ann['value']);
                 continue;
             }
         }
         //检查是否所有必须的参数均已绑定
         $invoker->check();
     }
     //属性注入
     /*foreach ($reflection->getProperties() as $property ){
           foreach ( $reader->getPropertyAnnotations($property) as $id => $ann){
               if($id !== 'inject') { continue;}
               $name = $property->getName();
               if($name == "ioc_factory"){// ioc_factory由工厂负责注入
                   //TODO: 用@ioc_factory替代ioc_factory
                   continue;
               }
               Verify::isTrue(count($ann) ===1, "$class::$name ambiguity @inject");
               Verify::isTrue(isset($ann[0]['value']), "$class::$name invalid @inject");
               Verify::isTrue(is_string($ann[0]['value']), "$class::$name invalid @inject");
               $this->injectors[] = new Injector($this, $name, $ann[0]['value']);
           }
       }*/
 }