Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/ray-di/Ray.Aop
An aspect-oriented framework for PHP
https://github.com/ray-di/Ray.Aop
aop aspect-oriented-programming guice interceptor
Last synced: 4 months ago
JSON representation
An aspect-oriented framework for PHP
- Host: GitHub
- URL: https://github.com/ray-di/Ray.Aop
- Owner: ray-di
- License: mit
- Created: 2011-10-16T18:10:01.000Z (over 12 years ago)
- Default Branch: 2.x
- Last Pushed: 2024-02-14T10:30:30.000Z (5 months ago)
- Last Synced: 2024-03-15T01:03:48.184Z (4 months ago)
- Topics: aop, aspect-oriented-programming, guice, interceptor
- Language: PHP
- Homepage: https://packagist.org/packages/ray/aop
- Size: 1.63 MB
- Stars: 99
- Watchers: 14
- Forks: 26
- Open Issues: 2
-
Metadata Files:
- Readme: README.ja.md
- Contributing: .github/CONTRIBUTING.md
- Funding: .github/FUNDING.yml
- License: LICENSE
- Security: .github/SECURITY.md
Lists
- awesome-stars - Ray.Aop - An aspect oriented framework for PHP (PHP)
- awesome-php - ray-di/Ray.Aop - An aspect-oriented framework for PHP (AOP)
README
# Ray.Aop
## アスペクト指向フレームワーク
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/ray-di/Ray.Aop/badges/quality-score.png?b=2.x)](https://scrutinizer-ci.com/g/Ray-Di/Ray.Aop/?branch=2.x)
[![codecov](https://codecov.io/gh/ray-di/Ray.Aop/branch/2.x/graph/badge.svg?token=KCQXtu01zc)](https://codecov.io/gh/ray-di/Ray.Aop)
[![Type Coverage](https://shepherd.dev/github/bearsunday/Ray.Aop/coverage.svg)](https://shepherd.dev/github/bearsunday/Ray.Aop)
[![Build Status](https://travis-ci.org/ray-di/Ray.Aop.svg?branch=2.x)](https://travis-ci.org/ray-di/Ray.Aop)
[![Total Downloads](https://poser.pugx.org/ray/aop/downloads)](https://packagist.org/packages/ray/aop)[\[English\]](https://github.com/ray-di/Ray.Aop/blob/2.x/README.md)
**Ray.Aop** パッケージはメソッドインターセプションの機能を提供します。マッチするメソッドが実行される度に実行されるコードを記述する事ができます。トランザクション、セキュリティやログといった横断的な”アスペクト”に向いています。なぜならインターセプターが問題をオブジェクトというよりアスペクトに分けるからです。これらの用法はアスペクト指向プログラミング(AOP)と呼ばれます。
[Matcher](https://github.com/ray-di/Ray.Aop/blob/2.x/src/MatcherInterface.php) は値を受け取ったり拒否したりするシンプルなインターフェイスです。例えばRay.Aopでは2つの **Matcher** が必要です。1つはどのクラスに適用するかを決め、もう1つはそのクラスのどのメソッドに適用するかを決めます。これらを簡単に利用するためのファクトリークラスがあります。
[MethodInterceptors](https://github.com/ray-di/Ray.Aop/blob/2.x/src/MethodInterceptor.php) はマッチしたメソッドが呼ばれる度に実行されます。呼び出しやメソッド、それらの引き数、インスタンスを調べる事ができます。横断的なロジックと委譲されたメソッドが実行されます。最後に返り値を調べて返します。インターセプターは沢山のメソッドに適用され沢山のコールを受け取るので、実装は効果的で透過的なものになります。
## 例:平日のメソッドコールを禁止する
メソッドインターセプターがRay.Aopでどのように機能するかを明らかにするために、週末にはピザの注文を禁止するようにしてみましょう。デリバリーは平日だけ受け付ける事にして、ピザの注文を週末には受け付けないようにします!この例はAOPで認証を使用するときにのパターンと構造的に似ています。
週末だけにするための[アノテーション](http://docs.doctrine-project.org/projects/doctrine-common/en/latest/reference/annotations.html)を定義します。
```php
proceed()` と実行します。```php
getMethod()->getName() . " not allowed on weekends!"
);
}
return $invocation->proceed();
}
}
```設定完了しました。このコードでは「どのクラスでも」「メソッドに`@NotOnWeekends`アノテーションがある」という条件にマッチします。
```php
any(),
(new Matcher())->annotatedWith(NotOnWeekends::class),
[new WeekendBlocker()]
);
$bind = (new Bind())->bind(RealBillingService::class, [$pointcut]);
$billing = (new Weaver($bind, $tmpDir))->newInstance(RealBillingService::class, [], $bind);try {
echo $billing->chargeOrder();
} catch (\RuntimeException $e) {
echo $e->getMessage() . "\n";
exit(1);
}
```全てをまとめ(土曜日まで待って)、メソッドをコールするとインターセプターにより拒否されます。
```
chargeOrder not allowed on weekends!
```## メソッド名を指定したマッチ
```php
bindInterceptors('chargeOrder', [new WeekendBlocker()]);
$compiler = new Weaver($bind, $tmpDir);
$billing = $compiler->newInstance('RealBillingService', [], $bind);
try {
echo $billing->chargeOrder();
} catch (\RuntimeException $e) {
echo $e->getMessage() . "\n";
exit(1);
}
```## 独自のマッチャー
独自のマッチャーを作成することもでます。
`contains` マッチャーを作成するためには、2つのメソッドを持つクラスを提供する必要があります。
1つはクラスのマッチを行う`matchesClass`メソッド、もう1つはメソッドのマッチを行う`matchesMethod`です。いずれもマッチしたかどうかをブールで返します。```php
use Ray\Aop\AbstractMatcher;class IsContainsMatcher extends AbstractMatcher
{
/**
* {@inheritdoc}
*/
public function matchesClass(\ReflectionClass $class, array $arguments) : bool
{
[$contains] = $arguments;return (strpos($class->name, $contains) !== false);
}/**
* {@inheritdoc}
*/
public function matchesMethod(\ReflectionMethod $method, array $arguments) : bool
{
[$contains] = $arguments;return (strpos($method->name, $contains) !== false);
}
}
``````php
$pointcut = new Pointcut(
(new Matcher())->any(),
new IsContainsMatcher('charge'),
[new WeekendBlocker()]
);
$bind = (new Bind)->bind(RealBillingService::class, [$pointcut]);
$billing = (new Weaver($bind, $tmpDir))->newInstance(RealBillingService::class, [$arg1, $arg2]);
```マッチャーはdoctrineアノテーション、またはPHP8アトリビュートの読み込みをサポートします。
```php
public function matchesClass(\ReflectionClass $class, array $arguments) : bool
{
assert($class instanceof \Ray\Aop\ReflectionClass);
$classAnnotation = $class->getAnnotation(Foo::class); // @Foo or #[Foo]
// ...
}public function matchesMethod(\ReflectionMethod $method, array $arguments) : bool
{
assert($method instanceof \Ray\Aop\ReflectionMethod);
$methodAnnotation = $method->getAnnotation(Bar::class);
}
```## パフォーマンス
`Weaver`オブジェクトはキャッシュ可能です。コンパイル、束縛、アノテーション読み込みコストを削減します。
```php
$weaver = unserialize(file_get_contentes('./serializedWeaver'));
$billing = (new Weaver($bind, $tmpDir))->newInstance(RealBillingService::class, [$arg1, $arg2]);
```## 優先順位
インターセプターの実行順は以下のルールで決定されます。
* 基本的にはバインドした順に実行されます。
* `PriorityPointcut`で定義したものが最も優先されます。
* アノテーションでメソッドマッチするものは`PriorityPointcut`の次に優先されます。その時アノテートされた順で優先されます。```php
/**
* @Auth // 1st
* @Cache // 2nd
* @Log // 3rd
*/
```## 制限
この機能の背後ではメソッドのインターセプションを事前にコードを生成する事で可能にしています。Ray.Aopはダイナミックにサブクラスを生成してメソッドをオーバーライドするインターセプターを適用します。
クラスとメソッドは以下のものである必要があります。
* クラスは *final* ではない
* メソッドは *public*## インターセプター
呼び出されたメソッドをそのまま実行するだけのインターセプターは以下のようになります。
```php
class MyInterceptor implements MethodInterceptor
{
public function invoke(MethodInvocation $invocation)
{
// メソッド実行前
//
// メソッド実行
$result = invocation->proceed();
// メソッド実行後
//
return $result;
}
}
```インターセプターに渡されるメソッド実行(`MethodInvocation`)オブジェクトは以下のメソッドを持ちます。
* [`$invocation->proceed()`](https://github.com/ray-di/Ray.Aop/blob/2.x/src/Joinpoint.php#L41) - メソッド実行
* [`$invocation->getMethod()`](https://github.com/ray-di/Ray.Aop/blob/2.x/src/MethodInvocation.php#L30) - メソッドリフレクションの取得
* [`$invocation->getThis()`](https://github.com/ray-di/Ray.Aop/blob/2.x/src/Joinpoint.php#L50) - オブジェクトの取得
* [`$invocation->getArguments()`](https://github.com/ray-di/Ray.Aop/blob/2.x/src/Invocation.php#L25) - 引数の取得
* [`$invocation->getNamedArguments()`](https://github.com/ray-di/Ray.Aop/blob/2.x/src/Invocation.php#L32) - 名前付き引数の取得拡張されたリフレクションはアノテーション取得のメソッドを持ちます。
```php
/** @var $method \Ray\Aop\ReflectionMethod */
$method = $invocation->getMethod();
/** @var $class \Ray\Aop\ReflectionClass */
$class = $invocation->getMethod()->getDeclaringClass();
```
* [`$method->getAnnotations()`]() - メソッドアノテーションの取得
* [`$method->getAnnotation($name)`]()
* [`$class->->getAnnotations()`]() - クラスアノテーションの取得
* [`$class->->getAnnotation($name)`]()## AOPアライアンス
このメソッドインターセプターのAPIは[AOPアライアンス](http://aopalliance.sourceforge.net/doc/org/aopalliance/intercept/MethodInterceptor.html)の部分実装です。
## インストール
Ray.Aopの推奨インストール方法は、[Composer](https://github.com/composer/composer)でのインストールです。
```bash
# Ray.Aop を依存パッケージとして追加する
$ composer require ray/aop ~2.0
```## パフォーマンス
AOPクラスのコンパイルにより、Ray.Aopは高速に動作します。アノテーションの読み込みは初回コンパイル時のみなので、ランタイムのパフォーマンスに影響を与えません。開発段階や最初の実行時にも、ファイルのタイムスタンプを利用してPHPファイルがキャッシュされ、通常はアノテーション生成のコストを気にする必要はありませんが、アプリケーションのブートストラップでアノテーションリーダーの設定を行うことで、初回コンパイル時のパフォーマンスが向上します。特に大規模なアプリケーションでこの設定は役立ちます。
### APCu
```php
SevericeLocator::setReader(new PsrCachedReader(new Reader(), $apcuCache));
```### アトリビュートのみ使用(推奨)
```php
SevericeLocator::setReader(new AttributeReader);`
```## DI Framework
DIとAOPを統合したDIフレームワーク[Ray.Di](https://github.com/ray-di/Ray.Di)もご覧ください。
* この文書の大部分は [Guice/AOP](https://github.com/google/guice/wiki/AOP) から借用しています。