Skip to content

Commit

Permalink
Merge pull request #85 from koriym/template
Browse files Browse the repository at this point in the history
Clean template with performance
  • Loading branch information
koriym authored Apr 27, 2018
2 parents 8b4efa5 + d755e75 commit 24a83d7
Show file tree
Hide file tree
Showing 11 changed files with 123 additions and 45 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ before_script:
script:
- ./vendor/bin/phpunit --coverage-clover=coverage.clover;
- if [ "$TRAVIS_PHP_VERSION" = "7.1" ]; then CHANGED_FILES=$(git diff --name-only --diff-filter=ACMRTUXB "${TRAVIS_COMMIT_RANGE}") & if ! echo "${CHANGED_FILES}" | grep -qE "^(\\.php_cs(\\.dist)?|composer\\.lock)$"; then IFS=$'\n' EXTRA_ARGS=('--path-mode=intersection' '--' ${CHANGED_FILES[@]}); fi & php php-cs-fixer-v2.phar fix --config=.php_cs -v --dry-run --stop-on-violation --using-cache=no "${EXTRA_ARGS[@]}"; fi
- if [ "$TRAVIS_PHP_VERSION" = "7.1" ]; then ./vendor/bin/phpstan analyse -l max src --no-progress --no-interaction; fi
- if [ "$TRAVIS_PHP_VERSION" = "7.1" ]; then ./vendor/bin/phpstan analyse -l max -c phpstan.neon src --no-progress --no-interaction; fi
after_script:
- if [ "$TRAVIS_PHP_VERSION" = "7.1" ]; then wget https://scrutinizer-ci.com/ocular.phar && php ocular.phar code-coverage:upload --format=php-clover coverage.clover; fi
2 changes: 2 additions & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
parameters:
excludes_analyse:
- %currentWorkingDirectory%/tests/tmp/*
ignoreErrors:
- '#Access to an undefined property PhpParser\\Node\\Expr::\$args#'
65 changes: 65 additions & 0 deletions src/AopTemplateConverter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

declare(strict_types=1);
/**
* This file is part of the Ray.Aop package.
*
* @license http://opensource.org/licenses/MIT MIT
*/
namespace Ray\Aop;

use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\ArrayItem;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Expr\Variable;

final class AopTemplateConverter extends \PhpParser\NodeVisitorAbstract
{
/**
* @var string
*/
private $method;

/**
* @var Arg[]
*/
private $args = [];

private $proceedArg;

public function __construct(\ReflectionMethod $method)
{
$this->method = $method->name;
$proceedArg = [];
foreach ($method->getParameters() as $parameter) {
$this->args[] = new Arg(new Variable($parameter->name));
$proceedArg[] = new ArrayItem(new Variable($parameter->name));
}
$this->proceedArg = new Arg(new Node\Expr\Array_($proceedArg));
}

public function enterNode(Node $node)
{
if ($node instanceof StaticCall && $node->name === 'templateMethod') {
$node->name = $this->method;
$node->args = $this->args;

return $node;
}

return $this->updateReflectiveMethodInvocation2ndParam($node);
}

private function updateReflectiveMethodInvocation2ndParam(Node $node) : Node
{
if ($node instanceof MethodCall && $node->name === 'proceed') {
$node->var->args[2] = $this->proceedArg;

return $node;
}

return $node;
}
}
13 changes: 0 additions & 13 deletions src/Arguments.php

This file was deleted.

12 changes: 9 additions & 3 deletions src/CodeGenMethod.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use PhpParser\Comment\Doc;
use PhpParser\Node\NullableType;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\NodeTraverser;
use PhpParser\Parser;
use PhpParser\PrettyPrinter\Standard;
use Ray\Aop\Annotation\AbstractAssisted;
Expand Down Expand Up @@ -100,7 +101,7 @@ private function getMethod(\ReflectionMethod $method)
if ($returnType instanceof \ReflectionType) {
$this->setReturnType($returnType, $methodStmt);
}
$methodInsideStatements = $this->getMethodInsideStatement();
$methodInsideStatements = $this->getMethodInsideStatement($method);
$methodStmt->addStmts($methodInsideStatements);

return $this->addMethodDocComment($methodStmt, $method);
Expand Down Expand Up @@ -135,14 +136,19 @@ private function addMethodDocComment(Method $methodStmt, \ReflectionMethod $meth
/**
* @return \PhpParser\Node[]
*/
private function getMethodInsideStatement() : array
private function getMethodInsideStatement(\ReflectionMethod $method) : array
{
$traverser = new NodeTraverser;
$traverser->addVisitor(new AopTemplateConverter($method));

$code = file_get_contents(dirname(__DIR__) . '/template/AopTemplate.php');
$node = $this->parser->parse($code)[0];
/* @var $node \PhpParser\Node\Stmt\Class_ */
$node = $node->getMethods()[0];
// traverse
$stmts = $traverser->traverse($node->stmts);

return $node->stmts;
return $stmts;
}

/**
Expand Down
23 changes: 12 additions & 11 deletions src/ReflectiveMethodInvocation.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ final class ReflectiveMethodInvocation implements MethodInvocation
private $object;

/**
* @var Arguments
* @var array|\ArrayObject
*/
private $arguments;

/**
* @var \ReflectionMethod
* @var string
*/
private $method;

Expand All @@ -32,14 +32,14 @@ final class ReflectiveMethodInvocation implements MethodInvocation

/**
* @param object $object
* @param \ReflectionMethod $method
* @param Arguments $arguments
* @param string $method
* @param array $arguments
* @param MethodInterceptor[] $interceptors
*/
public function __construct(
$object,
\ReflectionMethod $method,
Arguments $arguments,
string $method,
array $arguments,
array $interceptors = []
) {
$this->object = $object;
Expand All @@ -55,20 +55,22 @@ public function getMethod() : \ReflectionMethod
{
if ($this->object instanceof WeavedInterface) {
$class = (new \ReflectionObject($this->object))->getParentClass();
$method = new ReflectionMethod($class->name, $this->method->name);
$method->setObject($this->object, $this->method);
$method = new ReflectionMethod($class->name, $this->method);
$method->setObject($this->object, $method);

return $method;
}

return $this->method;
return new ReflectionMethod($this->object, $this->method);
}

/**
* {@inheritdoc}
*/
public function getArguments() : \ArrayObject
{
$this->arguments = new \ArrayObject($this->arguments);

return $this->arguments;
}

Expand All @@ -93,10 +95,9 @@ public function getNamedArguments() : \ArrayObject
public function proceed()
{
if ($this->interceptors === []) {
return $this->method->invokeArgs($this->object, $this->arguments->getArrayCopy());
return call_user_func_array([$this->object, $this->method], (array) $this->arguments);
}
$interceptor = array_shift($this->interceptors);
/* @var $interceptor MethodInterceptor */

return $interceptor->invoke($this);
}
Expand Down
20 changes: 7 additions & 13 deletions template/AopTemplate.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
* @see http://stackoverflow.com/questions/1796100/what-is-faster-many-ifs-or-else-if
* @see http://stackoverflow.com/questions/2401478/why-is-faster-than-in-php
*/

class AopTemplate extends \Ray\Aop\FakeMock implements Ray\Aop\WeavedInterface
{
/**
Expand All @@ -17,6 +18,7 @@ class AopTemplate extends \Ray\Aop\FakeMock implements Ray\Aop\WeavedInterface
* [$methodName => [$interceptorA[]][]
*/
public $bindings;

/**
* @var bool
*/
Expand All @@ -27,27 +29,19 @@ class AopTemplate extends \Ray\Aop\FakeMock implements Ray\Aop\WeavedInterface
*
* @param mixed $a
*/
public function returnSame($a)
public function templateMethod($a, $b)
{
if (isset($this->bindings[__FUNCTION__]) === false) {
return call_user_func_array('parent::' . __FUNCTION__, func_get_args());
}

if ($this->isIntercepting === false) {
$this->isIntercepting = true;

return call_user_func_array('parent::' . __FUNCTION__, func_get_args());
return parent::templateMethod($a, $b);
}

$this->isIntercepting = false;
$invocationResult = (new \Ray\Aop\ReflectiveMethodInvocation(
$this,
new \ReflectionMethod($this, __FUNCTION__),
new \Ray\Aop\Arguments(func_get_args()),
$this->bindings[__FUNCTION__]
))->proceed();
// invoke interceptor
$result = (new \Ray\Aop\ReflectiveMethodInvocation($this, __FUNCTION__, [$a, $b], $this->bindings[__FUNCTION__]))->proceed();
$this->isIntercepting = true;

return $invocationResult;
return $result;
}
}
10 changes: 10 additions & 0 deletions tests/CompilerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -261,4 +261,14 @@ public function testMethodAnnotationReaderReturnNull()
$this->assertNull(FakeMethodAnnotationReaderInterceptor::$methodAnnotation);
$this->assertCount(0, FakeMethodAnnotationReaderInterceptor::$methodAnnotations);
}

public function testInterceptorCanChangeArgument()
{
$bind = (new Bind)->bindInterceptors('returnSame', [new FakeChangeArgsInterceptor()]);
$compiler = new Compiler($_ENV['TMP_DIR']);
/** @var FakeMock $mock */
$mock = $compiler->newInstance(FakeMock::class, [], $bind);
$mock->returnSame(1);
$this->assertSame('changed', $mock->returnSame(1));
}
}
13 changes: 13 additions & 0 deletions tests/Fake/FakeChangeArgsInterceptor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php
namespace Ray\Aop;

class FakeChangeArgsInterceptor implements MethodInterceptor
{
public function invoke(MethodInvocation $invocation)
{
$args = $invocation->getArguments();
$args[0] = 'changed';

return $invocation->proceed();
}
}
2 changes: 1 addition & 1 deletion tests/Fake/FakeWeaved.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public function returnSame($a)
$invocation = new ReflectiveMethodInvocation(
$this,
new \ReflectionMethod($this, __FUNCTION__),
new Arguments(func_get_args()),
func_get_args(),
$interceptors
);

Expand Down
6 changes: 3 additions & 3 deletions tests/ReflectiveMethodInvocationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ protected function setUp()
{
parent::setUp();
$this->fake = new FakeClass;
$this->invocation = new ReflectiveMethodInvocation($this->fake, new \ReflectionMethod($this->fake, 'add'), new Arguments([1]));
$this->invocation = new ReflectiveMethodInvocation($this->fake, 'add', [1]);
}

public function testGetMethod()
Expand Down Expand Up @@ -70,7 +70,7 @@ public function testGetThis()
public function testGetParentMethod()
{
$fake = new FakeWeavedClass;
$invocation = new ReflectiveMethodInvocation($fake, new \ReflectionMethod($fake, 'add'), new Arguments([1]));
$invocation = new ReflectiveMethodInvocation($fake, 'add', [1]);
$method = $invocation->getMethod();
$this->assertSame(FakeClass::class, $method->class);
$this->assertSame('add', $method->name);
Expand All @@ -79,7 +79,7 @@ public function testGetParentMethod()
public function testProceedMultipleInterceptors()
{
$fake = new FakeWeavedClass;
$invocation = new ReflectiveMethodInvocation($fake, new \ReflectionMethod($fake, 'add'), new Arguments([1]), [new FakeInterceptor, new FakeInterceptor]);
$invocation = new ReflectiveMethodInvocation($fake, 'add', [1], [new FakeInterceptor, new FakeInterceptor]);
$invocation->proceed();
$this->assertSame(1, $fake->a);
}
Expand Down

0 comments on commit 24a83d7

Please sign in to comment.