Upgrade to Pro — share decks privately, control downloads, hide ads and more …

PHPにおけるアトリビュートの活用方法

will1992114
November 30, 2022

 PHPにおけるアトリビュートの活用方法

PHPerのための「PHPフレームワーク」を語り合うPHP TechCafe
で発表
https://rakus.connpass.com/event/264108/

will1992114

November 30, 2022
Tweet

Other Decks in Programming

Transcript

  1. PHPにおけるアトリ
    ビュートの活⽤⽅法
    株式会社ケアリッツ・テクノロジーズ
    栗原 駿
    2022/11/29

    View full-size slide

  2. ⾃⼰紹介
    • 名前:栗原 駿
    • 所属:株式会社ケアリッツ・テクノロジーズ
    • 主な経験⾔語:C#
    • PHPは業務で使い始めて半年ほどです。
    • 趣味:マラソン(最近全然⾛ってない…)
    • 最近はサウナにはまってます!

    View full-size slide

  3. 話すこと
    • PHPにおけるアトリビュートとは
    • 活⽤例①:バリデーションの共通化
    • 活⽤例②:ロギング処理の共通化

    View full-size slide

  4. PHPにおけるアトリビュートとは
    #[Description("アトリビュートの説明⽤のクラス")]
    class Example
    {
    #[Description("プロパティ")]
    public string $key;
    #[Description("メソッド")]
    public function execute( #[Description("引数")]$arg) : void { }
    }

    View full-size slide

  5. PHPにおけるアトリビュートとは
    • メタデータをコードの宣⾔時に埋め込むことができる
    • 実⾏時にリフレクションAPIで読み取って使⽤する
    • 様々な⽤途で使⽤できる
    • ロジックの共通化
    • IDEへの補助的な情報の通知
    • クラス、メソッド、関数、パラメータ、プロパティ、クラス定数に指定できる

    View full-size slide

  6. class SampleClass
    {
    public $keyA;
    public $keyB;
    public function __construct($keya, $keyb)
    {
    $this->keyA = $keya;
    $this->keyB = $keyb;
    if($this->keyA === null) {
    throw new Exception($property->getName() . "は必須のプロパティです。");
    }
    }
    }

    活⽤法①:バリデーションの共通化
    • コンストラクタ実⾏時のバリデーションをアトリビュートで共通化する。

    View full-size slide

  7. 活⽤法①:バリデーションの共通化
    class SampleClass
    {
    use Validator;
    #[Required]
    public $keyA;
    public $keyB;
    public function __construct($keya, $keyb)
    {
    $this->keyA = $keya;
    $this->keyB = $keyb;
    $this->validate($this);
    }

    View full-size slide

  8. 活⽤法①:バリデーションの共通化
    trait Validator
    {
    function validate($input): bool
    {
    $reflection = new ReflectionObject($input);
    foreach ($reflection->getProperties() as $key => $property) {
    $isRequired = $property->getAttributes(Required::class) > 0;
    if ($isRequired && $property->getValue($input) === null) {
    throw new Exception($property->getName() . "は必須のプロパティです。");
    }
    }

    View full-size slide

  9. 活⽤例②:ロギング処理の共通化
    • アトリビュートを付加したメソッドについて、
    実⾏開始時と完了時にログを出⼒する
    • Ray.Aopというフレームワークを使⽤する
    • AOP(アスペクト指向プログラミング)のための機能を提供する

    View full-size slide

  10. 活⽤例②:ロギング処理の共通化
    LogSample
    (処理を注⼊したいクラス)
    Log
    (処理の注⼊先を指定するア
    トリビュート)
    Ray.Aop
    LogInterceptor
    (注⼊する処理の実装)
    特定の関数に指定
    #[Log]を指定するクラスに対して、
    インスタンス化時にLogInterceptor
    を注⼊する

    View full-size slide

  11. 活⽤例②:ロギング処理の共通化
    #[Attribute(Attribute::TARGET_METHOD)]
    class Log
    {
    }
    class LogSample
    {
    #[Log]
    public function LogSample($arg1, $arg2)
    {
    echo ("LogSample() を実⾏しています" . "¥n");
    return "LogSample()のReturn";
    }

    View full-size slide

  12. 活⽤例②:ロギング処理の共通化
    class LogInterceptor implements MethodInterceptor
    {
    public function invoke(MethodInvocation $invocation)
    {
    // 処理実⾏前
    echo (date(DATE_ATOM) . ":" . $invocation->getMethod()->getName() . "の実⾏前 引数:"
    . json_encode($invocation->getArguments()) . "¥n");
    // 実処理の実⾏
    $result = $invocation->proceed();
    // 処理実⾏後
    echo (date(DATE_ATOM) . ":" . $invocation->getMethod()->getName() . "の実⾏後 戻り値:" .
    $result . "¥n");
    }

    View full-size slide

  13. 活⽤例②:ロギング処理の共通化
    $pointcut = new Pointcut(
    (new Matcher())->any(),
    (new Matcher())->annotatedWith(Log::class),
    [new LogInterceptor()]
    );
    $bind = (new Bind())->bind(LogSample::class, [$pointcut]);
    $tmpDir = __DIR__ . '/tmp';
    $sample = (new Weaver($bind, $tmpDir))->newInstance(LogSample::class, []);
    $sample->LogSample("arg1", "arg2");

    View full-size slide

  14. 活⽤例②:ロギング処理の共通化
    実⾏結果…
    > 2022-11-28T22:01:17+00:00:LogSampleの実⾏前 引数:{“0”:“arg1”,“1”:“arg2”} ←LogInterceptorのLog(実⾏前)
    > LogSample() を実⾏しています ←LogSampleのLog
    > 2022-11-28T22:01:17+00:00:LogSampleの実⾏後 戻り値:LogSample()のReturn ←LogInterceptorのLog(実⾏後)

    View full-size slide

  15. まとめ
    • PHPのアトリビュートを使うことでコードにメタデータを付加できる
    • 付加したメタデータを実⾏時に読み取ることでロジックの共通化ができる

    View full-size slide

  16. ご清聴ありがとうございました

    View full-size slide