Exemplo n.º 1
0
 /**
  * Execute $this->actions on methods
  * - rename will change the name of the method
  * - trait will ?
  */
 private function executeActions()
 {
     foreach ($this->actions as $method_name => $action) {
         if ($action == 'rename') {
             $regexp = Reflection_Method::regex($method_name);
             $this->class->source->setSource(preg_replace($regexp, LF . TAB . '$2' . LF . TAB . '/* $4 */ private $5 function $6$7_0$8$9', $this->class->source->getSource()));
         } elseif ($action == 'trait') {
             // TODO don't know what has to be done for this case
             trigger_error('Don\'t know how to ' . $action . SP . $this->class->name . '::' . $method_name, E_USER_NOTICE);
         } else {
             trigger_error('Don\'t know how to ' . $action . SP . $this->class->name . '::' . $method_name, E_USER_ERROR);
         }
     }
 }
Exemplo n.º 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 . ');';
     }
 }
Exemplo n.º 3
0
 /**
  * @param $method_name string
  * @param $advices     array
  * @return string
  */
 public function compile($method_name, $advices)
 {
     $methods = $this->class->getMethods([T_EXTENDS, T_IMPLEMENTS, T_USE]);
     if (!isset($methods[$method_name])) {
         trigger_error('AOP Compiler : Method does not exist ' . $this->class->name . '::' . $method_name . '()' . ' for advice ' . $this->displayAdvice(reset($advices)), E_USER_ERROR);
     }
     $source_method = $methods[$method_name];
     if (!$source_method) {
         trigger_error($this->class->name . '::' . $method_name . ' not found', E_USER_ERROR);
     }
     // don't compile abstract method where they are declared : will be compiled where they are
     // implemented
     if ($source_method->isAbstract()) {
         return '';
     }
     $class_name = $this->class->name;
     $buffer = $this->class->source->getSource();
     $result = '';
     if (self::DEBUG) {
         echo '<h3>Method ' . $class_name . '::' . $method_name . '</h3>';
     }
     $in_parent = !$this->class->implementsMethod($source_method->name);
     // preg expression to search and replace things into method prototype
     $preg_expr = Reflection_Method::regex($method_name);
     // $indent = prototype level indentation spaces
     $indent = $source_method instanceof Reflection_method ? $source_method->getIndent() : LF . TAB;
     $i2 = $indent . TAB;
     $i3 = $i2 . TAB;
     // $parameters = ['parameter_name' => 'parameter_name')
     $parameters = $source_method->getParametersNames();
     // $doc_comment = source method doc comment
     $doc_comment = $source_method->getDocComment();
     // $parameters_names = '$parameter1, $parameter2'
     $parameters_names = $parameters ? '$' . join(', $', $parameters) : '';
     // $prototype = 'public [static] function methodName($parameter1, $parameter2 = 'default')'
     $prototype = $source_method->getPrototypeString();
     /** $is_static = '[static]' */
     $is_static = $source_method->isStatic();
     /** @var $count integer around method counter */
     $count = null;
     // $joinpoint_has_return
     $joinpoint_has_return = strpos($doc_comment, '@return');
     // $pointcut_string
     if ($is_static) {
         $pointcut_string = '[get_called_class(), ' . Q . $method_name . Q . ']';
     } else {
         $pointcut_string = '[$this, ' . Q . $method_name . Q . ']';
     }
     // $code the generated code starts by the doc comments and prototype
     $after_code = [];
     $before_code = [];
     $advices_count = count($advices);
     $advice_number = 0;
     if (self::DEBUG && $in_parent) {
         echo 'in_parent = true for ' . $class_name . '::' . $method_name . BR;
     }
     $ref = $source_method->returnsReference() ? '&' : '';
     $call_code = $i2 . ($joinpoint_has_return ? '$result_ =' . $ref . SP : '') . ($is_static ? 'self::' : ($in_parent ? 'parent::' : '$this->')) . $method_name . ($in_parent ? '' : '_' . $count) . '(' . $parameters_names . ');';
     foreach (array_reverse($advices) as $advice) {
         $advice_number++;
         $type = $advice[0];
         if (self::DEBUG) {
             echo '<h4>' . $type . ' => ' . print_r($advice[1], true) . '</h4>';
         }
         /** @var $advice_class_name string */
         /** @var $advice_method_name string */
         /** @var $advice_function_name string */
         /** @var $advice_parameters string[] */
         /** @var $advice_string string [$object_, 'methodName') | 'functionName' */
         /** @var $advice_has_return boolean */
         /** @var $is_advice_static boolean */
         list($advice_class_name, $advice_method_name, $advice_function_name, $advice_parameters, $advice_string, $advice_has_return, $is_advice_static) = $this->decodeAdvice($advice[1], $class_name);
         // $advice_parameters_string, $joinpoint_code
         $joinpoint_code = '';
         if ($advice_parameters) {
             $advice_parameters_string = '$' . join(', $', array_keys($advice_parameters));
             if (isset($advice_parameters['result']) && !isset($parameters['result'])) {
                 $advice_parameters_string = str_replace('$result', '$result_', $advice_parameters_string);
             }
             if (isset($advice_parameters['object']) && !isset($parameters['object'])) {
                 $advice_parameters_string = str_replace('$object', '$this', $advice_parameters_string);
             }
             if (isset($advice_parameters['joinpoint'])) {
                 $advice_parameters_string = str_replace('$joinpoint', '$joinpoint_', $advice_parameters_string);
                 $joinpoint_parameters_string = '[';
                 $joinpoint_string_parameters = '';
                 foreach (array_values($parameters) as $key => $name) {
                     if ($key) {
                         $joinpoint_parameters_string .= ', ';
                     }
                     $joinpoint_parameters_string .= $key . ' => &$' . $name;
                     $joinpoint_string_parameters .= ', ' . Q . $name . Q . ' => &$' . $name;
                 }
                 $joinpoint_parameters_string .= $joinpoint_string_parameters . ']';
                 switch ($type) {
                     case 'after':
                         $joinpoint_code = $i2 . '$joinpoint_ = new \\SAF\\Framework\\AOP\\Joinpoint\\After_Method(' . $i3 . '__CLASS__, ' . $pointcut_string . ', ' . $joinpoint_parameters_string . ', $result_, ' . $advice_string . $i2 . ');';
                         break;
                     case 'around':
                         $process_callback = $methods[$method_name]->class->name == $this->class->name ? $method_name . '_' . $count : $method_name;
                         $joinpoint_code = $i2 . '$joinpoint_ = new \\SAF\\Framework\\AOP\\Joinpoint\\Around_Method(' . $i3 . '__CLASS__, ' . $pointcut_string . ', ' . $joinpoint_parameters_string . ', ' . $advice_string . ', ' . Q . $process_callback . Q . $i2 . ');';
                         break;
                     case 'before':
                         $joinpoint_code = $i2 . '$joinpoint_ = new \\SAF\\Framework\\AOP\\Joinpoint\\Before_Method(' . $i3 . '__CLASS__, ' . $pointcut_string . ', ' . $joinpoint_parameters_string . ', ' . $advice_string . $i2 . ');';
                         break;
                 }
             }
         } else {
             $advice_parameters_string = '';
         }
         $advice_code = $this->generateAdviceCode($advice, $advice_class_name, $advice_method_name, $advice_function_name, $advice_parameters_string, $advice_has_return, $is_advice_static, $joinpoint_code, $i2, '$result_');
         switch ($type) {
             case 'after':
                 if ($joinpoint_code) {
                     $advice_code .= $i2 . 'if ($joinpoint_->stop) return $result_;';
                 }
                 $after_code[] = $advice_code;
                 break;
             case 'around':
                 $my_prototype = $advice_number == $advices_count ? $prototype : str_replace($method_name, $method_name . '_' . $count, $prototype);
                 $result .= substr($indent, 1) . $my_prototype . substr($i2, 1) . $this->codeAssembly($before_code, $advice_code, $after_code, $indent) . ($joinpoint_has_return ? LF . $i2 . 'return $result_;' : '') . $indent . '}' . LF;
                 if ($advice_number < $advices_count) {
                     $count++;
                 }
                 $before_code = [];
                 $after_code = [];
                 break;
             case 'before':
                 if ($advice_has_return) {
                     $advice_code .= $i2 . 'if (isset($result_)) return $result_;';
                 }
                 if ($joinpoint_code) {
                     $advice_code .= $i2 . 'if ($joinpoint_->stop)) return $result_;';
                 }
                 $before_code[] = $advice_code;
                 break;
         }
     }
     if ($before_code || $after_code) {
         $result .= substr($indent, 1) . $prototype . substr($i2, 1) . $this->codeAssembly($before_code, $call_code, $after_code, $indent) . ($joinpoint_has_return ? LF . $i2 . 'return $result_;' : '') . $indent . '}' . LF;
     }
     $this->class->source->setSource(preg_replace($preg_expr, $indent . '$2' . $indent . '/* $4 */ private $5 function $6 $7_' . $count . '$8$9', $buffer), false);
     return $result;
 }