ray-di / ray.aop Goto Github PK
View Code? Open in Web Editor NEWAn aspect-oriented framework for PHP
Home Page: https://packagist.org/packages/ray/aop
License: MIT License
An aspect-oriented framework for PHP
Home Page: https://packagist.org/packages/ray/aop
License: MIT License
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;
}
}
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" にすることで解決するかと思います。
対応お願いします。
The reason is use of MD5 bind
object for identify binding.
Instead, use toString
. It is binding log. not changeable on each request.
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\apiclient
はnamespace
が未定義で、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の投稿先が間違っていましたら、
申し訳ございません。
お手数をおかけいたしますが、
ご確認の程、よろしくお願いいたします。
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:
MetaCrawlerService
as is MetaCrawlerService_XXX
MetaCrawlerService_XXX
extends CrawlerService
to CrawlerService_NXUWZ0A
MetaCrawlerService_KGlnUTY
extends MetaCrawlerService
to MetaCrawlerService_XXX
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|
/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
タイプヒントがついているのに$result
をreturn
してしまっている
public function chargeOrder() : void
{
...
return $result; // ouch!
}
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;
}
}
nullableな引数がある関数に対してアノテーションをつけると、コンパイルしたファイルには ?
が外れてしまい、実行時エラーになりました。
対象のfunction
/**
* Annotation()
*/
function run(?int $id): int {}
コンパイルされたコード
function run(int $id): int {}
See #180
it should be return reflection of source method.
#181 にて親クラスのメソッドのインターセプトが実装されましたが、
メソッドシグネチャにnamescpace外のクラスが記述されるとエラーになります。
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;
}
}
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!
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);
The use of injected annotation reader is recommended.
インジェクトしたアノテーションリーダーの使用を勧めます。
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.
無名クラスが含まれるコードはAOPコードをコンパイルできません。
Code that contains an anonymous class cannot compile AOP code.
class FakeAnonymousClass
{
public function hasAnonymousClass($a): object
{
return new class {};
}
}
Cuase Ray\Aop\Exception\MultipleClassInOneFileException
/Users/akihito/git/Ray.Aop/src/CodeVisitor.php:67
Weaved class should have doc comment block (class and method) as same as target class.
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;
}
Is it possible to use this framework to modify system functions/methods? Specifically, I was hoping to be able to modify the date()
function. Thank you!
Case: I use composer and every request your library recompiled all classes.
Line 79 in 8dcf395
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.
It should be
$weaver->a = 1;
$obj = $weave->___getObject();
var_duno($obj->a);
1 Expected
0 Actual
https://github.com/koriym/Ray.Aop/blob/develop/src/Ray/Aop/ReflectiveMethodInvocation.php#L114
このメソッドは実装しているインターフェイス(MethodInvocation, Invocation, Joinpoint)のどれでも定義されていないにもかかわらず、{@inheritdoc} とマークされています。
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.
当初はproxyとしてリリースされましたが、その後PHP-Parserを利用したcodegen方式へと進化し、AOPアラインアンスにも準拠した本格的なAOP環境を提供してきました。2015年の2.0のリリース以降は後方互換性を維持し続けています。
これから独自のcodegenエンジンを採用する予定です。初期のベンチマークでは、現在のPHP-Parserベースのものと比べて40倍以上の高速性能を発揮しています。
Compiler based on nikic/PHP-Parser
Compiler based on our own optimized engine
method annotation not working, not even in code generated if only on super class without adding it on subclass, even if the superclass is abstract
Generated sub class should have copied private property from parent.
It should have..
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()で取得しないとできない。速度は劣るが安全。
It seems rarely used. no more needed for api document parser ?
ReflectiveMethodInvocation::$args
should be access as ArrayObject
not array.
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
It seems that Matcher class has responsibility:
$matcher->subclassesOf()
__invoke
magic methodThis 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.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.