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

  2. ⾃⼰紹介 • 名前:栗原 駿 • 所属:株式会社ケアリッツ・テクノロジーズ • 主な経験⾔語:C# • PHPは業務で使い始めて半年ほどです。

    • 趣味:マラソン(最近全然⾛ってない…) • 最近はサウナにはまってます!
  3. 話すこと • PHPにおけるアトリビュートとは • 活⽤例①:バリデーションの共通化 • 活⽤例②:ロギング処理の共通化

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

    public function execute( #[Description("引数")]$arg) : void { } }
  5. PHPにおけるアトリビュートとは • メタデータをコードの宣⾔時に埋め込むことができる • 実⾏時にリフレクションAPIで読み取って使⽤する • 様々な⽤途で使⽤できる • ロジックの共通化 •

    IDEへの補助的な情報の通知 • クラス、メソッド、関数、パラメータ、プロパティ、クラス定数に指定できる
  6. <?php 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() . "は必須のプロパティです。"); } } } • 活⽤法①:バリデーションの共通化 • コンストラクタ実⾏時のバリデーションをアトリビュートで共通化する。
  7. 活⽤法①:バリデーションの共通化 <?php class SampleClass { use Validator; #[Required] public $keyA;

    public $keyB; public function __construct($keya, $keyb) { $this->keyA = $keya; $this->keyB = $keyb; $this->validate($this); }
  8. 活⽤法①:バリデーションの共通化 <?php 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() . "は必須のプロパティです。"); } }
  9. 活⽤例②:ロギング処理の共通化 • アトリビュートを付加したメソッドについて、 実⾏開始時と完了時にログを出⼒する • Ray.Aopというフレームワークを使⽤する • AOP(アスペクト指向プログラミング)のための機能を提供する

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

    #[Log]を指定するクラスに対して、 インスタンス化時にLogInterceptor を注⼊する
  11. 活⽤例②:ロギング処理の共通化 #[Attribute(Attribute::TARGET_METHOD)] class Log { } class LogSample { #[Log]

    public function LogSample($arg1, $arg2) { echo ("LogSample() を実⾏しています" . "¥n"); return "LogSample()のReturn"; }
  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"); }
  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");
  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(実⾏後)
  15. まとめ • PHPのアトリビュートを使うことでコードにメタデータを付加できる • 付加したメタデータを実⾏時に読み取ることでロジックの共通化ができる

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