Coder Social home page Coder Social logo

ray.aop's People

Contributors

apple-x-co avatar fiahfy avatar iteman avatar izayoi256 avatar kawahara avatar kenjis avatar koriym avatar kuma-guy avatar mackstar avatar madapaja avatar momospnr avatar mugeso avatar naokitsuchiya avatar polidog avatar sasezaki avatar scrutinizer-auto-fixer avatar wand2016 avatar wyrihaximus avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ray.aop's Issues

Matcher:: createMatcher()

Own matcher

You can have your own matcher.
To create contains matcher, You need to provide a class which have two method. One is contains for interface.
The other one is isContains which return the result of the contains match.

use Ray\Aop\AbstractMatcher;

class MyMatcher extends AbstractMatcher
{
    /**
     * @param $contain
     *
     * @return MyMatcher
     */
    public function contains($contain)
    {
        $this->createMatcher(__FUNCTION__, $contain);

        return clone $this;

    }

    /**
     * Return isContains
     *
     * @param $name    class or method name
     * @param $target  \Ray\Aop\AbstractMatcher::TARGET_CLASS | \Ray\Aop\AbstractMatcher::Target_METHOD
     * @param $contain
     *
     * @return bool
     */
    protected function isContains($name, $target, $contain)
    {
        $result = (strpos($name, $contain) !== false);

        return $result;
    }
}

Composerでの依存性解決エラー

php composer.phar install 時に下記エラーが発生します。

Your requirements could not be solved to an installable set of packages.

  Problem 1
    - The requested package doctrine/common 2.3.* could not be found.

Potential causes:
 - A typo in the package name
 - The package is not available in a stable-enough version according to your minimum-stability setting
   see https://groups.google.com/d/topic/composer-dev/_g3ASeIFlrc/discussion for more details.

https://github.com/koriym/Ray.Aop/blob/master/composer.json#L17 のdoctrine/commonバージョンを、
"2.3.x-dev" にすることで解決するかと思います。

対応お願いします。

Google_Client(google\apiclient)の読み込みエラー

Bear.Sunday経由でRay.Aopを利用しておりますが、
google\apiclientと組み合わせて利用した際に下記のエラーが発生します。

1) kght6123\ossnote\Resource\App\GloginTest::testOnGet
The use statement with non-compound name 'Google_Client' has no effect

/Users/kogahirotaka/develop/bear.sunday/kght6123.ossnotes/backend/var/tmp/app/di/kght6123_ossnote_Resource_App_Glogin_JxlmmSE.php:26
/Users/kogahirotaka/develop/bear.sunday/kght6123.ossnotes/backend/vendor/ray/aop/src/Compiler.php:119
/Users/kogahirotaka/develop/bear.sunday/kght6123.ossnotes/backend/vendor/ray/aop/src/Compiler.php:119
/Users/kogahirotaka/develop/bear.sunday/kght6123.ossnotes/backend/vendor/ray/aop/src/Compiler.php:82
/Users/kogahirotaka/develop/bear.sunday/kght6123.ossnotes/backend/vendor/ray/di/src/Dependency.php:117
/Users/kogahirotaka/develop/bear.sunday/kght6123.ossnotes/backend/vendor/ray/compiler/src/OnDemandCompiler.php:61
/Users/kogahirotaka/develop/bear.sunday/kght6123.ossnotes/backend/vendor/ray/compiler/src/ScriptInjector.php:235
/Users/kogahirotaka/develop/bear.sunday/kght6123.ossnotes/backend/vendor/ray/compiler/src/ScriptInjector.php:196
/Users/kogahirotaka/develop/bear.sunday/kght6123.ossnotes/backend/vendor/ray/compiler/src/ScriptInjector.php:138
/Users/kogahirotaka/develop/bear.sunday/kght6123.ossnotes/backend/vendor/bear/resource/src/AppAdapter.php:56
/Users/kogahirotaka/develop/bear.sunday/kght6123.ossnotes/backend/vendor/bear/resource/src/Factory.php:46
/Users/kogahirotaka/develop/bear.sunday/kght6123.ossnotes/backend/vendor/bear/resource/src/Resource.php:95
/Users/kogahirotaka/develop/bear.sunday/kght6123.ossnotes/backend/tests/Resource/App/GloginTest.php:21

ERRORS!
Tests: 3, Assertions: 20, Errors: 1.
Script phpunit handling the test event returned with error code 2

google\apiclientnamespaceが未定義で、autoload.phpを利用して解決しますが
その際にRay.Aopを経由すると、Google_Clientクラスがエラーで解決できないと想定しています。

試しにuse Google_Client;を除去すると、下記のnot foundエラーになります。

1) kght6123\ossnote\Resource\App\GloginTest::testOnGet
Error: Class 'kght6123\ossnote\Resource\App\Google_Client' not found

/Users/kogahirotaka/develop/bear.sunday/kght6123.ossnotes/backend/src/Resource/App/Glogin.php:83
/Users/kogahirotaka/develop/bear.sunday/kght6123.ossnotes/backend/var/tmp/app/di/kght6123_ossnote_Resource_App_Glogin_JxlmmSE.php:39
/Users/kogahirotaka/develop/bear.sunday/kght6123.ossnotes/backend/vendor/ray/aop/src/ReflectiveMethodInvocation.php:110
/Users/kogahirotaka/develop/bear.sunday/kght6123.ossnotes/backend/src/Interceptor/BenchMarker.php:23
/Users/kogahirotaka/develop/bear.sunday/kght6123.ossnotes/backend/vendor/ray/aop/src/ReflectiveMethodInvocation.php:114
/Users/kogahirotaka/develop/bear.sunday/kght6123.ossnotes/backend/var/tmp/app/di/kght6123_ossnote_Resource_App_Glogin_JxlmmSE.php:43
/Users/kogahirotaka/develop/bear.sunday/kght6123.ossnotes/backend/vendor/bear/resource/src/Invoker.php:41
/Users/kogahirotaka/develop/bear.sunday/kght6123.ossnotes/backend/vendor/bear/resource/src/AbstractRequest.php:144
/Users/kogahirotaka/develop/bear.sunday/kght6123.ossnotes/backend/vendor/bear/resource/src/Resource.php:146
/Users/kogahirotaka/develop/bear.sunday/kght6123.ossnotes/backend/tests/Resource/App/GloginTest.php:24

ERRORS!
Tests: 3, Assertions: 20, Errors: 1.
Script phpunit handling the test event returned with error code 2

下記はコードの抜粋です。

namespace kght6123\ossnote\Resource\App;

require __DIR__ . '/../../../vendor/autoload.php';

use Google_Client;// has no effect

class Glogin extends BaseResourceObject {
  public function onPost(string $userid, string $password, string $path): ResourceObject {
    $client = new Google_Client();// not found error.
  }
}

フルバージョンのコードは下記で公開しております。
https://github.com/kght6123/ossnotes/blob/master/backend/src/Resource/App/Glogin.php

可能であれば修正していただけますでしょうか?

コードの記述が想定と異なっていたり、
Issuesの投稿先が間違っていましたら、
申し訳ございません。

お手数をおかけいたしますが、
ご確認の程、よろしくお願いいたします。

Don't work extend compiled parent

Sources:

class MetaCrawlerService extends CrawlerService

CrawlerService and MetaCrawlerService have pointcuts. But after compiling gets:

class MetaCrawlerService_KGlnUTY extends MetaCrawlerService implements WeavedInterface
abstract class CrawlerService_NXUWZ0A extends CrawlerService implements WeavedInterface

I expected that MetaCrawlerService_KGlnUTY will extend CrawlerService_NXUWZ0A or something similar.

Workaround:

  • copy MetaCrawlerService as is MetaCrawlerService_XXX
  • replace in MetaCrawlerService_XXX extends CrawlerService to CrawlerService_NXUWZ0A
  • replace in MetaCrawlerService_KGlnUTY extends MetaCrawlerService to MetaCrawlerService_XXX
  • in all methods of CrawlerService_NXUWZ0A replace
        if (!$this->isAspect) {
            $this->isAspect = true;
            call_user_func_array([$this, 'parent::' . __FUNCTION__], func_get_args());
            return;
        }

to

        if (!$this->isAspect) {
            $this->isAspect = true;

            $class = (new \ReflectionObject($this))->getParentClass();

            $rc1 = new \ReflectionClass($class->name);

            do {
                $method = new \ReflectionMethod($rc1->getParentClass()->name, __FUNCTION__);
                $rc1 = new \ReflectionClass($method->class);
            } while($rc1->implementsInterface(WeavedInterface::class) );

            $method = new \ReflectionMethod($rc1->name, __FUNCTION__);
            $method->invokeArgs($this, func_get_args());
            
            return;
        }

Without this gets exception:

Symfony\Component\Debug\Exception\FatalThrowableError  : Maximum function nesting level of '256' reached, aborting!

  at /var/www/app/vendor/ray/aop/src/ReflectiveMethodInvocation.php:110
    106|     {
    107|         if ($this->interceptors === [] && \is_callable($this->callable)) {
    108|             return call_user_func_array($this->callable, (array) $this->arguments);
    109|         }
  > 110|         $interceptor = array_shift($this->interceptors);
    111|         if ($interceptor instanceof MethodInterceptor) {
    112|             return $interceptor->invoke($this);
    113|         }
    114|

php7.1のvoid関数が利用できない

PHP7.1新機能/void 関数

再現方法

  • /demo/src/AnnotationRealBillingService.phpを一部改変
<?php
declare(strict_types=1);
namespace Ray\Aop\Demo;
class AnnotationRealBillingService implements BillingService
{
    /**
     * @WeekendBlock
     */
-   public function chargeOrder()
+   public function chargeOrder(): void
    {
        echo "Charged.\n";
    }
}
  • /demo/03-annotation-bind.php を実行
php --version
PHP 7.2.19-0ubuntu0.18.04.2 (cli) (built: Aug 12 2019 19:34:28) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.2.19-0ubuntu0.18.04.2, Copyright (c) 1999-2018, by Zend Technologies
php 03-annotation-bind.php
PHP Fatal error:  A void function must not return a value in /home/wand/Desktop/learn/repos/Ray.Aop/demo/tmp/Ray_Aop_Demo_AnnotationRealBillingService_NXhGYhg.php on line 22

コンパイル後のファイル

<?php

declare (strict_types=1);
namespace Ray\Aop\Demo;

use Ray\Aop\WeavedInterface;
use Ray\Aop\ReflectiveMethodInvocation as Invocation;
class AnnotationRealBillingService_NXhGYhg extends \Ray\Aop\Demo\AnnotationRealBillingService implements BillingService, WeavedInterface
{
    public $bind;
    public $bindings = [];
    public $methodAnnotations = 'a:1:{s:11:"chargeOrder";a:1:{i:0;O:25:"Ray\\Aop\\Demo\\WeekendBlock":0:{}}}';
    public $classAnnotations = 'a:0:{}';
    private $isAspect = true;
    /**
     * @WeekendBlock
     */
    public function chargeOrder() : void
    {
        if (!$this->isAspect) {
            $this->isAspect = true;
            return call_user_func_array([$this, 'parent::' . __FUNCTION__], func_get_args());
        }
        $this->isAspect = false;
        $result = (new Invocation($this, __FUNCTION__, func_get_args(), $this->bindings[__FUNCTION__]))->proceed();
        $this->isAspect = true;
        return $result;
    }
}

:void タイプヒントがついているのに$resultreturnしてしまっている

    public function chargeOrder() : void
    {
        ...
        return $result;  // ouch!
    }

Organizing the generated AOP code

Current version:

class FakeMock_358616026 extends \Ray\Aop\FakeMock implements WeavedInterface
{
    public $bind;
    public $bindings = [];
    public $methodAnnotations = 'a:0:{}';
    public $classAnnotations = 'a:0:{}';
    public $isAspect = true;
    /**
     * doc comment of returnSame
     */
    public function returnSame($a)
    {
        if (!$this->isAspect) {
            $this->isAspect = true;
            return call_user_func_array([parent::class, __FUNCTION__], func_get_args());
        }
        $this->isAspect = false;
        $result = (new Invocation($this, __FUNCTION__, func_get_args(), $this->bindings[__FUNCTION__]))->proceed();
        $this->isAspect = true;
        return $result;
    }
}

Update version:

class FakeMock_358616026 extends \Ray\Aop\FakeMock implements WeavedInterface
{
    use AopTrait;

    /**
     * doc comment of returnSame
     */
    public function returnSame($a)
    {
        return $this->__aop(func_get_args(), __FUNCTION__);
    }
}
<?php

namespace Ray\Aop;

use Ray\Aop\ReflectiveMethodInvocation as Invocation;
use function call_user_func_array;
use function func_get_args;

trait AopTrait
{
    private $bind;
    private $bindings = [];
    public $methodAnnotations = 'a:0:{}';
    public $classAnnotations = 'a:0:{}';
    private $isAspect = true;

    private function __aop(array $args, string $func)
    {
        if (!$this->isAspect) {
            $this->isAspect = true;
            return call_user_func_array([parent::class, __FUNCTION__], func_get_args());
        }
        $this->isAspect = false;
        $result = (new Invocation($this, __FUNCTION__, func_get_args(), $this->bindings[__FUNCTION__]))->proceed();
        $this->isAspect = true;
        return $result;
    }
}

何が得られるか?

  • デバックトレースの時の読みやすさ、ステップ実行のしやすさ
  • レンダリング速度
    • php parserを使わなくてもいいかも? (依存を減らすことができるかもしれない)

php7.1のnullabe引数が利用できない

nullableな引数がある関数に対してアノテーションをつけると、コンパイルしたファイルには ? が外れてしまい、実行時エラーになりました。

対象のfunction

/**
 * Annotation()
 */
function run(?int $id): int {}

コンパイルされたコード

function run(int $id): int {}

Wrong compiled method of parent

Bug Report

#181 にて親クラスのメソッドのインターセプトが実装されましたが、
メソッドシグネチャにnamescpace外のクラスが記述されるとエラーになります。

How to reproduce

demo/src に以下の2つのクラスを作成します。

<?php
declare(strict_types=1);

namespace Ray\Aop\Demo;

use ArrayIterator;
use Traversable;

class A
{
    public function passIterator(ArrayIterator $iterator): Traversable
    {
        return $iterator;
    }
}
<?php
declare(strict_types=1);

namespace Ray\Aop\Demo;

class B extends A
{
}

demo に以下のファイルを作成し、実行します。

<?php

use Ray\Aop\NullInterceptor;

require __DIR__ . '/bootstrap.php';

$compiler = new Ray\Aop\Compiler(__DIR__ . '/tmp');
$bind = (new Ray\Aop\Bind())->bindInterceptors('passIterator', [new NullInterceptor()]);
$b = $compiler->newInstance(Ray\Aop\Demo\B::class, [], $bind);
$b->passIterator(new ArrayIterator());
PHP Fatal error:  Could not check compatibility between Ray\Aop\Demo\B_3617677882::passIterator(Ray\Aop\Demo\ArrayIterator $iterator): Ray\Aop\Demo\Traversable and Ray\Aop\Demo\A::passIterator(ArrayIterator $iterator): Traversable, because class Ray\Aop\Demo\ArrayIterator is not available in /Users/tsuchiya/work/tsuchiya/Ray.Aop/demo/tmp/Ray_Aop_Demo_B_3617677882.php on line 15

Fatal error: Could not check compatibility between Ray\Aop\Demo\B_3617677882::passIterator(Ray\Aop\Demo\ArrayIterator $iterator): Ray\Aop\Demo\Traversable and Ray\Aop\Demo\A::passIterator(ArrayIterator $iterator): Traversable, because class Ray\Aop\Demo\ArrayIterator is not available in /Users/tsuchiya/work/tsuchiya/Ray.Aop/demo/tmp/Ray_Aop_Demo_B_3617677882.php on line 15

生成されたクラスは以下です。

<?php

declare (strict_types=1);
namespace Ray\Aop\Demo;

use Ray\Aop\WeavedInterface;
use Ray\Aop\ReflectiveMethodInvocation as Invocation;
class B_3617677882 extends \Ray\Aop\Demo\B implements WeavedInterface
{
    public $bind;
    public $bindings = [];
    public $methodAnnotations = 'a:0:{}';
    public $classAnnotations = 'a:0:{}';
    private $isAspect = true;
    public function passIterator(ArrayIterator $iterator) : Traversable
    {
        if (!$this->isAspect) {
            $this->isAspect = true;
            return call_user_func_array([$this, 'parent::' . __FUNCTION__], func_get_args());
        }
        $this->isAspect = false;
        $result = (new Invocation($this, __FUNCTION__, func_get_args(), $this->bindings[__FUNCTION__]))->proceed();
        $this->isAspect = true;
        return $result;
    }
}

Annotation cache

Hi,

I was wondering what your thoughts are regarding the hardcoded AnnotationReader in Bind.php. Would you guys be open to have a reader as a possible constructor argument for example?

In my case I would like to use the CachedReader instead for performance.

PS: Great library!

Matcher::setAnnotationReader($reader)

Enable to set cached annotation reader for Matcher.
This annotation set statically for further use at Matcher.

<?php

use Doctrine\Common\Annotations\CachedReader;
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Cache\ApcCache;

$reader = new CachedReader(new AnnotationReader(new ApcCache));
Matcher::setAnnotationReader($reader);

Matcher::startsWith()

Matcher interface need to updated for correct method name.

Updated

public function startsWith($prefix);

Deprecated

public function startWith($prefix);

BC should not break with this change.

Can't compile with anonymous class

Bug Report

無名クラスが含まれるコードはAOPコードをコンパイルできません。

Code that contains an anonymous class cannot compile AOP code.

How to reproduce

class FakeAnonymousClass
{
    public function hasAnonymousClass($a): object
    {
        return new class {};
    }
}

Cuase Ray\Aop\Exception\MultipleClassInOneFileException
/Users/akihito/git/Ray.Aop/src/CodeVisitor.php:67

Docblox copy

Weaved class should have doc comment block (class and method) as same as target class.

Add Compiler::noBindNewInstance()

Interceptor can be attached after aspect class creation.

This function is necessary to avoid interceptor's affect at dependency injection. (=setter method can't bind interceptor)

Sample code is like as below.

$instance = $compiler->noBindNewInstance($definition->class, $params, $bind);
$hasBinding = $bind->hasBinding();

// setter injection here
// ....

 // attach interceptors
if ($hasBinding) {
    $instance->rayAopBind = $bind;
}

Why autoload param disabled for class_exists in Compiler.php ?

Case: I use composer and every request your library recompiled all classes.

if (class_exists($aopClassName, false)) {

        if (class_exists($aopClassName, false)) {
class_exists ( string $class_name [, bool $autoload = TRUE ] ) : bool

This function checks whether or not the given class has been defined.

class_name
The class name. The name is matched in a case-insensitive manner.

autoload
Whether or not to call __autoload by default.

ytake/Laravel-Aspect#63

🎉 10 years

🎉 It's been over 10 years since the initial release of Ray.Aop.

Initially released as a proxy, it later evolved to use the PHP-Parser for a codegen approach, providing a full-fledged AOP environment that also adheres to the AOP Alliance standards. Since its 2.0 release in 2015, it has continuously maintained backward compatibility.

We plan to use our own codegen engine. Initial benchmarks show performance more than 40 times faster than the current PHP-Parser based one.

🎉 Ray.Aopの最初のリリースから10年以上が経過しました。

当初はproxyとしてリリースされましたが、その後PHP-Parserを利用したcodegen方式へと進化し、AOPアラインアンスにも準拠した本格的なAOP環境を提供してきました。2015年の2.0のリリース以降は後方互換性を維持し続けています。

これから独自のcodegenエンジンを採用する予定です。初期のベンチマークでは、現在のPHP-Parserベースのものと比べて40倍以上の高速性能を発揮しています。


Compiler based on nikic/PHP-Parser

php-parser based 2023-09-17 19 50 28

Compiler based on our own optimized engine

costum codegen 2023-09-17 19 50 40

Error with variadic parameters

The cause was refactoring to use the original argument as it is for speeding up.
This is wrong, and it can not do such a thing when it is a variable argument, and can not do it without getting with func_get_args (). Slow but safe.

原因は高速化のために、元の引数をそのまま使おうとしたリファクタリング。
これが間違っていて、可変引数の時はそのようなことができずfunc_get_args()で取得しないとできない。速度は劣るが安全。

Upgrade has lead to the following error

Catchable fatal error: Argument 1 passed to Ray\Aop\Matcher::__construct() must implement interface Doctrine\Common\Annotations\Reader, none given, called in /Users/MackstarMBA/Sites/ProjectZulu/vendor/ray/di/src/AbstractModule.php on line 193 and defined in /Users/MackstarMBA/Sites/ProjectZulu/vendor/ray/aop/src/Matcher.php on line 54

Matcher class has too many responsibility

It seems that Matcher class has responsibility:

  1. a DSL interface e.g. $matcher->subclassesOf()
  2. do verify constraints via __invoke magic method

This means current implementation violates the SRP.
Especially, it's a very violation that Macher class verifies various constrains.

So, I suggest refactoring Matcher class like PHPUnit.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.