Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug Fixes: Refined logic for managing execution depth and interception state #9

Merged
merged 31 commits into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
d052a53
Refactor object access for parameter preparation.
koriym Dec 6, 2024
eb4b10e
Add debug print statements within conditional compilation
koriym Dec 6, 2024
efdb2bb
Refactor RayAOP to improve error handling and performance
koriym Dec 7, 2024
efc8bbe
Simplify exception and interception handling logic
koriym Dec 7, 2024
9faf1be
Enhance execution data validation and error handling
koriym Dec 7, 2024
5bae335
Refactor function names for consistency
koriym Dec 7, 2024
d0a05a0
Refactor interception logic and improve exception handling
koriym Dec 7, 2024
7bffe61
Configure build with debug flags.
koriym Dec 7, 2024
e9e3c72
Enable method interception in rayaop test
koriym Dec 7, 2024
42ae90b
Refactor variable naming in thread safety test
koriym Dec 7, 2024
b92b3f3
fixup! Enable method interception in rayaop test
koriym Dec 7, 2024
1af55cc
Improve test result validation and messaging
koriym Dec 8, 2024
77810d3
Free thread-safe global ID after allocation
koriym Dec 8, 2024
39d00dd
fixup! Improve test result validation and messaging
koriym Dec 8, 2024
ef8af08
Handle void returns in user function calls
koriym Dec 8, 2024
865d6e6
Enable method intercept in thread safety test
koriym Dec 8, 2024
535b748
Add test for RayAOP void return handling.
koriym Dec 8, 2024
be7f484
Improve error handling in interceptor execution
koriym Dec 8, 2024
c1397d6
Update rayaop.cFix potential use-after-free in thread safety initiali…
koriym Dec 8, 2024
1a6f8c0
Add demo and debug functions to build script
koriym Dec 8, 2024
3f2e7b4
Add comprehensive error handling and debug options
koriym Dec 8, 2024
a16f5f7
Add demo using Ray.Aop for Aspect-Oriented Programming
koriym Dec 9, 2024
0135526
Add tests and memory checks for demo directory
koriym Dec 9, 2024
e93e054
fixup! Add demo using Ray.Aop for Aspect-Oriented Programming
koriym Dec 9, 2024
458c2d8
Add support for PHP 8.4 in GitHub Actions workflow
koriym Dec 9, 2024
dccadcb
Improve error messaging for interceptor failures
koriym Dec 9, 2024
3d5abd3
Remove redundant mutex allocation check
koriym Dec 9, 2024
3344101
Update demo/src/BillingService.php
koriym Dec 9, 2024
dea7e8e
Check for spprintf failure in key generation
koriym Dec 9, 2024
9e8d774
fix: potential memory leak during parameter preparation
koriym Dec 9, 2024
cf5ffbf
Prevent interception of internal functions
koriym Dec 9, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 34 additions & 19 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:

strategy:
matrix:
php-version: ['8.1', '8.2', '8.3']
php-version: ['8.1', '8.2', '8.3', '8.4']

steps:
- name: Checkout code
Expand Down Expand Up @@ -50,8 +50,17 @@ jobs:
timeout 60s php -n -dextension=./modules/rayaop.so -dmemory_limit=128M -dreport_memleaks=1 -dzend.assertions=1 -dassert.exception=1 smoke.php
continue-on-error: true

# Add demo directory test
- name: Test demo directory
id: test_demo_dir
run: |
cd demo
composer install
php -dextension=../modules/rayaop.so aop.php
continue-on-error: true

- name: Run Valgrind memory check
if: steps.run_tests.outcome == 'failure' || steps.run_demo.outcome == 'failure'
if: steps.run_tests.outcome == 'failure' || steps.run_demo.outcome == 'failure' || steps.test_demo_dir.outcome == 'failure'
run: |
cat << EOF > valgrind.supp
{
Expand All @@ -65,27 +74,32 @@ jobs:
EOF
valgrind --suppressions=valgrind.supp --leak-check=full --show-leak-kinds=all --track-origins=yes --verbose --log-file=valgrind-out.txt php -n -dextension=./modules/rayaop.so smoke.php

# Also run Valgrind on demo directory
cd demo
valgrind --suppressions=../valgrind.supp --leak-check=full --show-leak-kinds=all --track-origins=yes --verbose --log-file=valgrind-demo-out.txt php -n -dextension=../modules/rayaop.so aop.php

- name: Check Valgrind results
if: steps.run_tests.outcome == 'failure' || steps.run_demo.outcome == 'failure'
if: steps.run_tests.outcome == 'failure' || steps.run_demo.outcome == 'failure' || steps.test_demo_dir.outcome == 'failure'
run: |
if [ -f valgrind-out.txt ]; then
echo "Valgrind log found:"
cat valgrind-out.txt
if ! grep -q "ERROR SUMMARY: 0 errors from 0 contexts" valgrind-out.txt; then
echo "Valgrind found errors"
exit 1
for log in valgrind-out.txt demo/valgrind-demo-out.txt; do
if [ -f "$log" ]; then
echo "Checking Valgrind log: $log"
cat "$log"
if ! grep -q "ERROR SUMMARY: 0 errors from 0 contexts" "$log"; then
echo "Valgrind found errors in $log"
exit 1
fi
fi
else
echo "Valgrind log not found. This is unexpected."
exit 1
fi
done

- name: Upload Valgrind log file
if: (steps.run_tests.outcome == 'failure' || steps.run_demo.outcome == 'failure') && always()
- name: Upload Valgrind logs
if: (steps.run_tests.outcome == 'failure' || steps.run_demo.outcome == 'failure' || steps.test_demo_dir.outcome == 'failure') && always()
uses: actions/upload-artifact@v4
with:
name: valgrind-log
path: valgrind-out.txt
name: valgrind-logs
path: |
valgrind-out.txt
demo/valgrind-demo-out.txt
if-no-files-found: warn

- name: Upload test logs
Expand All @@ -96,12 +110,13 @@ jobs:
path: |
tests/*.log
tests/*.sh
demo/*.log
if-no-files-found: warn

- name: Final status check
if: always()
run: |
if [ "${{ steps.run_tests.outcome }}" == "failure" ] || [ "${{ steps.run_demo.outcome }}" == "failure" ]; then
echo "Tests or demo run failed. Please check the logs for more information."
if [ "${{ steps.run_tests.outcome }}" == "failure" ] || [ "${{ steps.run_demo.outcome }}" == "failure" ] || [ "${{ steps.test_demo_dir.outcome }}" == "failure" ]; then
echo "Tests, demo run, or demo directory test failed. Please check the logs for more information."
exit 1
fi
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,6 @@
/Makefile.objects
/cmake-build-debug
/modules/rayaop.so

/demo/vendor/
/demo/tmp/
212 changes: 164 additions & 48 deletions README.ja.md
Original file line number Diff line number Diff line change
@@ -1,134 +1,250 @@
# Ray.Aop PHP拡張
# Ray.Aop PHP拡張機能

[![Build and Test PHP Extension](https://github.com/ray-di/ext-rayaop/actions/workflows/build.yml/badge.svg)](https://github.com/ray-di/ext-rayaop/actions/workflows/build.yml)

<img src="https://ray-di.github.io/images/logo.svg" alt="ray-di logo" width="150px;">

[Ray.Aop](https://github.com/ray-di/Ray.Aop)のためのコアメソッドインターセプション機能を提供する低レベルのPHP拡張です。この拡張は単体での使用も可能ですが、Ray.Aopのより高度なAOP機能の基盤として設計されています。
[Ray.Aop](https://github.com/ray-di/Ray.Aop)のコアとなるメソッドインターセプション機能を提供する低レベルPHP拡張機能です。この拡張機能は単独でも使用できますが、Ray.Aopのより高度なAOP機能の基盤として設計されています。

## 特徴

- 効率的な低レベルメソッドインターセプション
- finalクラスおよびメソッドのインターセプトをサポート
- 引数および戻り値の完全な変更サポート
- `new`キーワードとのシームレスな互換性
- スレッドセーフな操作サポート
- finalクラスやメソッドのインターセプトに対応
- パラメータと戻り値の完全な変更サポート
- `new`キーワードとのシームレスな連携
- スレッドセーフな動作のサポート
- 包括的なエラーハンドリングとデバッグ機能
- 適切なリソース管理による効率的なメモリ使用

## 要件

- PHP 8.1以上
- Linux、macOS、またはWindowsでの適切なビルドツール
- マルチスレッド環境ではスレッドセーフなPHPビルドを推奨
- Linux、macOS、またはWindows(適切なビルドツールが必要)
- マルチスレッド環境では、スレッドセーフビルドのPHPを推奨

## インストール

1. リポジトリをクローンします:
1. リポジトリのクローン:
```bash
git clone https://github.com/ray-di/ext-rayaop.git
cd ext-rayaop
```

2. 拡張をビルドし、インストールします:
2. ビルドとインストール:
```bash
phpize
./configure
make
make install
```

3. php.iniファイルに次の行を追加します:
3. php.iniに以下の行を追加:
```ini
extension=rayaop.so # Unix/Linuxの場合
extension=rayaop.dll # Windowsの場合
extension=rayaop.so # Unix/Linux用
extension=rayaop.dll # Windows用

; オプション: デバッグモードの有効化
; rayaop.debug_level = 1
```

4. インストールを確認します:
4. インストールの確認:
```bash
php -m | grep rayaop
```

## API リファレンス

### コア関数

#### method_intercept_init()
インターセプションシステムを初期化します。インターセプターの登録前に必ず呼び出す必要があります。

```php
bool method_intercept_init()
```

成功時は`true`、失敗時は`false`を返します。

#### method_intercept()
特定のクラスメソッドにインターセプターを登録します。

```php
bool method_intercept(string $class_name, string $method_name, Ray\Aop\MethodInterceptorInterface $interceptor)
```

- すでにインターセプターが登録されている場合は上書きされます
- 成功時は`true`、失敗時は`false`を返します

#### method_intercept_enable()
メソッドインターセプションをグローバルに有効/無効にします。

```php
void method_intercept_enable(bool $enable)
```

### スレッドセーフティ

この拡張機能は完全にスレッドセーフで、以下の機構を使用しています:

- ミューテックスによるリソース保護
- グローバル状態用のスレッドローカルストレージ
- マルチスレッド環境での安全な初期化とクリーンアップ

マルチスレッド環境(PHP-FPMなど)での使用時の注意点:
- PHPでZTS(Zend Thread Safety)が有効になっていることを確認
- 各スレッドが独自のインターセプション状態を維持
- リソースのクリーンアップは自動的にスレッドごとに処理

## エラーハンドリング

### エラーコード

拡張機能は以下のエラーコードを定義しています:

- `RAYAOP_E_MEMORY_ALLOCATION (1)`: メモリ割り当て失敗
- `RAYAOP_E_HASH_UPDATE (2)`: ハッシュテーブル更新失敗
- `RAYAOP_E_INVALID_HANDLER (3)`: 無効なインターセプターハンドラー
- `RAYAOP_E_MAX_DEPTH_EXCEEDED (4)`: 最大インターセプション深度超過
- `RAYAOP_E_NULL_POINTER (5)`: NULLポインターエラー
- `RAYAOP_E_INVALID_STATE (6)`: 無効な内部状態

エラーはPHPのエラー報告システムを通じて報告されます。これらのエラーをキャッチして処理するには、エラー報告を有効にしてください。

## デバッグモード

php.iniでデバッグレベルを設定することでデバッグモードを有効にできます:

```ini
rayaop.debug_level = 1
```

デバッグ出力には以下が含まれます:
- インターセプター登録イベント
- メソッドインターセプションのトレース
- リソースの割り当て/解放
- エラー条件とスタックトレース

## パフォーマンスに関する考慮事項

### 実行深度

無限再帰を防ぐため、最大インターセプション深度に制限があります:
```php
#define MAX_EXECUTION_DEPTH 100
```

ネストされたインターセプターを設計する際は、この制限を考慮してください。

### メモリ管理

拡張機能は慎重なメモリ管理を実装しています:
- インターセプターリソースの自動クリーンアップ
- PHPオブジェクトの適切な参照カウント
- インターセプター置換時の即時リソース解放
- リクエスト終了時のクリーンアップ

### パフォーマンスへの影響

メソッドインターセプションによるオーバーヘッド:
- 直接のメソッド呼び出し:約0.1-0.2μsの追加オーバーヘッド
- 単純なインターセプターでの呼び出し:約1-2μsのオーバーヘッド
- 複雑なインターセプターは実装に応じてより多くのオーバーヘッドが発生する可能性があります

パフォーマンスに関するヒント:
- インターセプターはアプリケーション初期化時に登録
- インターセプターの頻繁な登録/解除を避ける
- パフォーマンスが重要なコードには単純なインターセプターを使用
- 必要のない場合はインターセプションを無効化

## 設計の決定

この拡張は、最小限で高パフォーマンスなメソッドインターセプション機能を提供します。
この拡張機能は、最小限の高性能メソッドインターセプション機能を提供します:

- メソッドごとに1つのインターセプター:各メソッドに対して最後に登録されたインターセプターが優先されます
- finalクラスサポート:純粋なPHP実装と異なり、finalクラスおよびメソッドをインターセプト可能
- 素のインターセプション:組み込みのマッチングや条件はありません(これらの機能はRay.Aopで提供されます)
- スレッドセーフ:PHP-FPMなどのマルチスレッド環境でも安全に使用可能
- メソッドあたり1つのインターセプター:最後に登録されたインターセプターが優先されます
- 新しいインターセプターを登録すると、以前のものは自動的に解除されます
- この設計により、予測可能な動作と最適なパフォーマンスを確保
- finalクラスのサポート:Pure PHP実装では不可能なfinalクラスやメソッドのインターセプトが可能
- 生のインターセプション:組み込みのマッチングや条件はなし(これらの機能にはRay.Aopを使用)
- スレッドセーフ:PHP-FPMなどのマルチスレッド環境で安全に使用可能

## Ray.Aopとの関係

この拡張は低レベルのメソッドインターセプションを提供し、[Ray.Aop](https://github.com/ray-di/Ray.Aop)は高レベルのAOP機能を提供します
この拡張機能は低レベルのメソッドインターセプションを提供し、[Ray.Aop](https://github.com/ray-di/Ray.Aop)は高レベルのAOP機能を提供します

Ray.Aopが提供する機能
- マッチャーを用いた条件付きインターセプション
- メソッドごとの複数インターセプター
Ray.Aopの提供する機能
- Matchersを使用した条件付きインターセプション
- メソッドあたり複数のインターセプター
- 属性/アノテーションベースのインターセプション
- 高度なAOP機能

両方を併用する場合
両者を併用する場合
- Ray.Aopが高レベルのAOPロジックを処理
- この拡張が低レベルのインターセプション機構を提供
- Ray.Aopは、パフォーマンス向上のためにこの拡張を自動的に利用
- この拡張機能が低レベルのインターセプション機構を提供
- Ray.Aopは可能な場合、パフォーマンス向上のためにこの拡張機能を自動的に利用

## 基本的な使い方
## 基本的な使用方法

### シンプルなインターセプター
```php
class LoggingInterceptor implements Ray\Aop\MethodInterceptorInterface
{
public function intercept(object $object, string $method, array $params): mixed
{
echo "Before {$method}\n";
echo "実行前 {$method}\n";
$result = $object->$method(...$params);
echo "After {$method}\n";
echo "実行後 {$method}\n";
return $result;
}
}

// インターセプターを登録
method_intercept(TestClass::class, 'testMethod', new LoggingInterceptor());
```

### メソッドインターセプションの設定
```php
// インターセプションシステムを初期化
// 初期化とインターセプションの有効化
method_intercept_init();

// メソッドインターセプションを有効化
method_intercept_enable(true);

// インターセプターを登録
method_intercept(MyClass::class, 'myMethod', new MyInterceptor());
// インターセプターの登録
method_intercept(TestClass::class, 'testMethod', new LoggingInterceptor());
```

## 開発

### ビルドスクリプト
```bash
./build.sh clean # ビルド環境をクリーン
./build.sh prepare # ビルド環境を準備
./build.sh build # 拡張をビルド
./build.sh run # 拡張を実行
./build.sh all # 全てのステップを実行
./build.sh clean # ビルド環境のクリーン
./build.sh prepare # ビルド環境の準備
./build.sh build # 拡張機能のビルド
./build.sh run # 拡張機能の実行
./build.sh all # すべての手順を実行
```

### テスト
```bash
make test
```

特定のテストを実行する場合:
特定のテストの実行:
```bash
make test TESTS="-v tests/your_specific_test.phpt"
```

## 既知の制限事項

1. メソッドあたり1つのインターセプターのみ
2. 実行深度の最大値は100レベル
3. メソッドインターセプションのパターンマッチング機能なし
4. インターセプターはメソッドごとに個別に登録が必要

## ライセンス

[MIT License](LICENSE)
[MITライセンス](LICENSE)

## 作者

Akihito Koriyama

この拡張は、AIペアプログラミングの支援を受けて開発され、PHP拡張開発およびPECL基準に関する複雑さを克服するのに役立ちました。
この拡張機能は、PHP拡張機能開発とPECL標準の複雑さをナビゲートするのに役立つAIペアプログラミングの支援を受けて開発されました。

## 謝辞

このプロジェクトは[JetBrains CLion](https://www.jetbrains.com/clion/)を使用して作成されました。CLionは[オープンソースライセンス](https://www.jetbrains.com/community/opensource/)で無料で利用できます。

強力で使いやすい開発環境を提供してくださったJetBrainsに感謝いたします。
Loading
Loading