Example #1
0
 /**
  * Extends the list of sources to compile
  *
  * When you modify a file, all these classes may have their matching mysql structure changed :
  * - the class itself
  * - all classes that extend the class or use the trait
  *
  * @param &$sources Reflection_Source[]
  * @return Reflection_Source[] added sources list
  */
 public function moreSourcesToCompile(&$sources)
 {
     $added = [];
     // Builder is disabled during the listing as we want to get the original linked class name when
     // reading class annotation @link
     Builder::current()->enabled = false;
     /** @var $search Dependency */
     $search = Search_Object::create(Dependency::class);
     $search->file_name = Func::notLike('cache/%');
     $search->type = Func::orOp([Dependency::T_EXTENDS, Dependency::T_USE]);
     foreach ($sources as $source) {
         foreach ($source->getClasses() as $class) {
             while ($linked_class = $class->getAnnotation('link')->value) {
                 $source = Reflection_Class::of($linked_class)->source;
                 if (!isset($sources[$source->file_name])) {
                     $sources[$source->file_name] = $source;
                     $added[$source->file_name] = $source;
                 }
                 $class = $source->getClass($linked_class);
             }
             $search->dependency_name = $class->name;
             foreach (Dao::search($search, Dependency::class) as $dependency) {
                 /** @var $dependency Dependency */
                 if (!isset($sources[$dependency->file_name])) {
                     $source = new Reflection_Source($dependency->file_name);
                     $sources[$dependency->file_name] = $source;
                     $added[$dependency->file_name] = $source;
                 }
             }
         }
     }
     Builder::current()->enabled = true;
     return $added;
 }
Example #2
0
 /**
  * @param $advice                   string[]|object[]|string
  * @param $advice_class_name        string
  * @param $advice_method_name       string
  * @param $advice_function_name     string
  * @param $advice_parameters_string string
  * @param $advice_has_return        boolean
  * @param $is_advice_static         boolean
  * @param $joinpoint_code           string
  * @param $i2                       string
  * @param $result                   string
  * @return string
  */
 private function generateAdviceCode($advice, $advice_class_name, $advice_method_name, $advice_function_name, $advice_parameters_string, $advice_has_return, $is_advice_static, $joinpoint_code, $i2, $result)
 {
     // $advice_code
     if (is_array($advice)) {
         $methods_flags = [Reflection_Class::T_DOC_EXTENDS, T_EXTENDS, T_USE];
         $method = $advice[0] == '$this' ? $this->class->getMethods($methods_flags)[$advice_method_name] : Reflection_Method::of($advice_class_name, $advice_method_name, $methods_flags);
         $ref = $method->returnsReference() ? '&' : '';
         // static method call
         if ($is_advice_static) {
             return $joinpoint_code . $i2 . ($advice_has_return ? $result . SP . '=' . $ref . SP : '') . (in_array($advice[0], ['self', 'static']) ? $advice[0] : BS . $advice_class_name) . '::' . $advice_method_name . '(' . $advice_parameters_string . ');';
         } elseif ($advice[0] == '$this') {
             return $joinpoint_code . $i2 . ($advice_has_return ? $result . SP . '=' . $ref . SP : '') . '$this->' . $advice_method_name . '(' . $advice_parameters_string . ');';
         } else {
             return $i2 . '/** @var $object_ ' . BS . $advice_class_name . ' */' . $i2 . '$object_ = \\SAF\\Framework\\Session::current()->plugins->get(' . "'{$advice_class_name}'" . ');' . $joinpoint_code . $i2 . ($advice_has_return ? 'if ($object_) ' . $result . SP . '=' . $ref . SP : '') . '$object_->' . $advice_method_name . '(' . $advice_parameters_string . ');';
         }
     } else {
         $ref = (new ReflectionFunction($advice_function_name))->returnsReference() ? '&' : '';
         return $joinpoint_code . $i2 . ($advice_has_return ? $result . SP . '=' . $ref . SP : '') . $advice_function_name . '(' . $advice_parameters_string . ');';
     }
 }
Example #3
0
 /**
  * @param $class_name        string The base class name
  * @param $interfaces_traits string[] The interfaces and traits names list
  * @param $get_source        boolean if true, get built [$name, $source] instead of $name
  * @return string|string[] the full name of the built class
  */
 public static function build($class_name, $interfaces_traits = [], $get_source = false)
 {
     $key = join(DOT, $interfaces_traits);
     if (isset(self::$builds[$class_name][$key])) {
         return self::$builds[$class_name][$key];
     } else {
         $interfaces = [];
         $traits = [];
         foreach ($interfaces_traits as $interface_trait) {
             $class = Reflection_Class::of($interface_trait);
             if ($class->isInterface()) {
                 $interfaces[$interface_trait] = $interface_trait;
             } elseif ($class->isTrait()) {
                 foreach ($class->getListAnnotation('implements')->values() as $implements) {
                     $interfaces[$implements] = $implements;
                 }
                 $level = 0;
                 foreach ($class->getListAnnotation('extends')->values() as $extends) {
                     if (Dao::search(['class_name' => $extends, 'declaration' => Dependency::T_TRAIT_DECLARATION], Dependency::class)) {
                         foreach ($traits as $trait_level => $trait_names) {
                             if (isset($trait_names[$extends])) {
                                 $level = max($level, $trait_level + 1);
                             }
                         }
                     }
                 }
                 $traits[$level][$interface_trait] = $interface_trait;
             } else {
                 trigger_error('Unknown interface/trait ' . DQ . $interface_trait . DQ . ' while building ' . $class_name, E_USER_ERROR);
             }
         }
         $built_class = self::buildClass($class_name, $interfaces, $traits, $get_source);
         if (!$get_source) {
             self::$builds[$class_name][$key] = $built_class;
         }
         return $built_class;
     }
 }
Example #4
0
 /**
  * @param $properties array
  * @param $class      Reflection_Class
  */
 private function scanForImplements(&$properties, Reflection_Class $class)
 {
     // properties from the class and its direct traits
     $implemented_properties = $class->getProperties([T_USE]);
     foreach ($implemented_properties as $property) {
         $expr = '%' . '\\n\\s+\\*\\s+' . '@(getter|link|setter)' . '(?:\\s+' . '(?:([\\\\\\w]+)::)?' . '(\\w+)' . ')?' . '%';
         preg_match_all($expr, $property->getDocComment(), $match);
         foreach ($match[1] as $type) {
             $type = $type == 'setter' ? 'write' : 'read';
             $properties[$property->name]['implements'][$type] = true;
         }
         if ($property->getParent()) {
             $properties[$property->name]['override'] = true;
         }
     }
     // properties overridden into the class and its direct traits
     $documentations = $class->getDocComment([T_USE]);
     foreach ($this->scanForOverrides($documentations, ['getter', 'link', 'setter']) as $match) {
         $properties[$match['property_name']]['implements'][$match['type']] = true;
         if (!isset($implemented_properties[$match['property_name']])) {
             $class_properties = $class->getProperties([T_EXTENDS]);
             $extends = $class;
             while (!isset($class_properties[$match['property_name']])) {
                 // TODO try the error to have a class with @representative and property names that do not exist. That will crash here but the error message is incomprehensible
                 $extends = $extends->source->getOutsideClass($extends->getListAnnotation('extends')->values()[0]);
                 $class_properties = $extends->getProperties([T_EXTENDS]);
             }
             $property = $class_properties[$match['property_name']];
             if (isset($extends)) {
                 $property->final_class = $class->name;
             }
             if (!strpos($property->getDocComment(), '@getter') && !strpos($property->getDocComment(), '@link') && !strpos($property->getDocComment(), '@setter')) {
                 $expr = '%@override\\s+' . $match['property_name'] . '\\s+.*(@getter|@link|@setter)%';
                 preg_match($expr, $property->class->getDocComment(), $match2);
                 if ($match2) {
                     $properties[$match['property_name']]['override'] = true;
                 }
             }
         }
     }
 }
Example #5
0
 /**
  * Gets a single or multiple class type as its Reflection_Class
  *
  * @param $reflection_class_name string Any reflection class name that implements Reflection_Class
  * @return Interfaces\Reflection_Class
  */
 public function asReflectionClass($reflection_class_name = null)
 {
     if ($reflection_class_name) {
         return is_a($reflection_class_name, PHP\Reflection_Class::class, true) ? PHP\Reflection_Class::of($this->getElementTypeAsString()) : (new Reflection_Class($reflection_class_name))->newInstance($this->getElementTypeAsString());
     }
     return new Reflection_Class($this->getElementTypeAsString());
 }
Example #6
0
 /**
  * @param $doc_comment       string
  * @param $annotation_name   string
  * @param $i                 integer
  * @param $annotation_class  string
  * @param $reflection_object Has_Doc_Comment|Reflection
  * @return Annotation
  */
 private static function parseAnnotationValue($doc_comment, $annotation_name, &$i, $annotation_class, Reflection $reflection_object)
 {
     $i += strlen($annotation_name) + 1;
     $next_char = $doc_comment[$i];
     switch ($next_char) {
         case SP:
         case TAB:
             $i++;
             $j = strlen($doc_comment);
             $next_annotation = strpos($doc_comment, SP . '* @', $i);
             $end_doc_comment = strpos($doc_comment, SP . '*/', $i);
             $next_in = strpos($doc_comment, LF . self::DOC_COMMENT_IN, $i);
             if ($next_annotation !== false && $next_annotation < $j) {
                 $j = $next_annotation;
             }
             if ($end_doc_comment !== false && $end_doc_comment < $j) {
                 $j = $end_doc_comment;
             }
             if ($next_in !== false && $next_in < $j) {
                 $j = $next_in;
             }
             if ($j === false) {
                 trigger_error('Missing doc_comment end', E_USER_ERROR);
             }
             $value = trim(preg_replace('%\\s*\\n\\s+\\*\\s*%', '', substr($doc_comment, $i, $j - $i)));
             break;
         case CR:
         case LF:
             $value = true;
             break;
         default:
             $value = null;
     }
     /** @var $annotation Annotation */
     $annotation = isset($value) ? new $annotation_class($value, $reflection_object, $annotation_name) : null;
     if (isset($annotation) && isA($annotation, Annotation_In::class)) {
         /** @var $annotation Annotation_In */
         $j = strrpos(substr($doc_comment, 0, $i), LF . self::DOC_COMMENT_IN);
         if ($j === false) {
             $annotation->class_name = $reflection_object instanceof Reflection_Class_Component ? $reflection_object->getDeclaringClassName() : $reflection_object->getName();
         } else {
             $j += strlen(self::DOC_COMMENT_IN) + 1;
             $k = strpos($doc_comment, LF, $j);
             $annotation->class_name = substr($doc_comment, $j, $k - $j);
         }
     }
     if (isset($annotation) && isA($annotation, Types_Annotation::class)) {
         $do = false;
         if (is_array($annotation->value)) {
             foreach ($annotation->value as $value) {
                 if ($value && (ctype_upper($value[0]) || $value[0] == BS)) {
                     $do = true;
                     break;
                 }
             }
         } else {
             $do = $annotation->value && ctype_upper($annotation->value[0]);
         }
         if ($do) {
             /** @var $annotation Types_Annotation */
             $j = strrpos(substr($doc_comment, 0, $i), LF . self::DOC_COMMENT_IN);
             if ($j === false) {
                 $class_name = $reflection_object instanceof Reflection_Class_Component ? $reflection_object->getDeclaringClassName() : $reflection_object->getName();
                 $namespace = Namespaces::of($class_name);
                 $use = PHP\Reflection_Class::of($class_name)->getNamespaceUse();
             } else {
                 $j += strlen(self::DOC_COMMENT_IN) + 1;
                 $k = strpos($doc_comment, LF, $j);
                 $in_class = substr($doc_comment, $j, $k - $j);
                 $namespace = Namespaces::of($in_class);
                 $use = PHP\Reflection_Class::of($in_class)->getNamespaceUse();
             }
             $annotation->applyNamespace($namespace, $use);
         } elseif (is_array($annotation->value)) {
             foreach ($annotation->value as $key => $value) {
                 $annotation->value[$key] = Builder::className($value);
             }
         } else {
             if ($annotation->value[0] === BS) {
                 $annotation->value = substr($annotation->value, 1);
             }
             $annotation->value = Builder::className($annotation->value);
         }
     }
     return $annotation;
 }
Example #7
0
 /**
  * @param $property Reflection_Property
  * @return Reflection_Class
  */
 private function getForeignClass(Reflection_Property $property)
 {
     $type = $property->getType();
     $foreign_class_name = Builder::className($type->getElementTypeAsString());
     if ($property instanceof PHP\Reflection_Property) {
         $foreign_class = PHP\Reflection_Class::of($foreign_class_name);
     } else {
         $reflection_class = new Reflection\Reflection_Class(get_class($property->getDeclaringClass()));
         $foreign_class = $reflection_class->newInstance($foreign_class_name);
     }
     return $foreign_class;
 }
Example #8
0
 /**
  * TODO property you'd better do this into the last @override field @$annotation_name class
  *
  * @param $class_property  Reflection
  * @param $type_annotation Type_Annotation
  * @param $value           string
  * @param $pos             integer
  */
 private function searchIntoFinalClass(Reflection $class_property, Type_Annotation $type_annotation, $value, $pos)
 {
     $class = $class_property instanceof Reflection_Property ? $class_property->getFinalClass() : $class_property;
     trigger_error(sprintf('Looking namespace use for Method_Annotation into final class %1 for property %2' . ' is not reliable', $class->getName(), $class_property->getName()), E_USER_WARNING);
     $php_class = Reflection_Class::of($class->getName());
     $type_annotation->value = substr($value, 0, $pos);
     $type_annotation->applyNamespace($class->getNamespaceName(), $php_class->getNamespaceUse());
 }
Example #9
0
 /**
  * @param $class_name    string
  * @param $property_name string
  * @param $flags         integer[] T_EXTENDS, T_USE
  * @return Reflection_Method
  */
 public static function of($class_name, $property_name, $flags = [])
 {
     $properties = Reflection_Class::of($class_name)->getProperties($flags);
     return isset($properties[$property_name]) ? $properties[$property_name] : null;
 }
Example #10
0
 /**
  * Gets the classes that are into @extends instead of use to allow diamond multiple inheritance
  *
  * @return Reflection_Class[]
  */
 public function getDocExtends()
 {
     $extends = [];
     $expr = '%' . '\\n\\s+\\*\\s+' . '@extends' . '\\s+([\\\\\\w]+)' . '%';
     if (preg_match_all($expr, $this->getDocComment(), $matches)) {
         foreach ($matches[1] as $match) {
             $extends[] = Reflection_Class::of($this->fullClassName($match));
         }
     }
     return $extends;
 }
Example #11
0
 /**
  * @param $class_name  string
  * @param $method_name string
  * @param $flags       integer[] T_EXTENDS, T_IMPLEMENTS, T_USE
  * @return Reflection_Method
  */
 public static function of($class_name, $method_name, $flags = [])
 {
     $class = Reflection_Class::of($class_name);
     $methods = $class->getMethods($flags);
     if (!isset($methods[$method_name]) && in_array(T_EXTENDS, $flags)) {
         do {
             $class = $class->source->getOutsideClass($class->getListAnnotation('extends')->values()[0]);
             $methods = $class->getMethods($flags);
         } while (!isset($methods[$method_name]));
     }
     return $methods[$method_name];
 }
Example #12
0
 /**
  * @param $properties array
  * @param $class      Reflection_Class
  */
 private function scanForSetters(&$properties, Reflection_Class $class)
 {
     foreach ($class->getProperties() as $property) {
         $expr = '%' . '\\n\\s+\\*\\s+' . '@setter' . '(?:\\s+(?:([\\\\\\w]+)::)?' . '(\\w+)?)?' . '%';
         preg_match($expr, $property->getDocComment(), $match);
         if ($match) {
             $advice = [empty($match[1]) ? '$this' : $class->source->fullClassName($match[1]), empty($match[2]) ? Names::propertyToMethod($property->name, 'set') : $match[2]];
             $properties[$property->name][] = ['write', $advice];
         }
     }
     foreach ($this->scanForOverrides($class->getDocComment(), ['setter']) as $match) {
         $advice = [empty($match['class_name']) ? '$this' : $match['class_name'], empty($match['method_name']) ? Names::propertyToMethod($match['property_name'], 'set') : $match['method_name']];
         $properties[$match['property_name']][] = ['write', $advice];
     }
 }