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

PHP 9 に備えよ - 動的プロパティ、どうすればいぃ?

PHP 9 に備えよ - 動的プロパティ、どうすればいぃ?

taisuke arase

May 10, 2024
Tweet

Other Decks in Technology

Transcript

  1. 動的型付け言語に多く見られる // js class User {} const user = new

    User(); user.name = "udon"; // 新しいプロパティを追加 # python class User: pass user = User() user.name = "udon" # 新しい属性を追加 動的プロパティが非推奨になった話 6
  2. 他の言語では宣言が必要な場合が多い // Java public class User { // プロパティは事前に定義する必要がある private

    String name; } // swift class User { // プロパティは事前に定義する必要がある var name: String } 動的プロパティが非推奨になった話 7
  3. class User { public $name; } $user = new User;

    // Assigns declared property User::$name. $user->name = "foo"; // Oops, a typo: $user->nane = "foo"; // PHP <= 8.1: Silently creates dynamic $user->nane property. // PHP 8.2: Raises deprecation warning, still creates dynamic property. // PHP 9.0: Throws Error exception. PHP 8.2 から非推奨になり、PHP 9.0 からは例外が投げられるようにな ります 動的プロパティが非推奨になった話 https://wiki.php.net/rfc/deprecate_dynamic_properties より 10
  4. 結論 大抵の場合は PHPStan を使えば検出できそうです ただし、コードが複雑なプロダクトの場合は PHPStan だけでは拾えない パターンもあったので、Phan や PhpStorm

    などの他の解析ツールも併用 すると良さそうです つまり静的解析も完璧ではなさそうなので、検知できなくて実際に動かし てみたら動的プロパティだった、みたいなこともありうると思います 動的プロパティは静的解析で検知できるのか 16
  5. PHPStan での動的プロパティの検出1 Access to an undefined property として検出できます class Foo

    {} $foo = new Foo(); $foo->test = 'oh my'; // Access to an undefined property Foo::$test. echo $foo->test; ただしコードによっては動的プロパティ以前の問題として検出されてしま うので注意が必要です 動的プロパティは静的解析で検知できるのか https://phpstan.org/blog/phpstan-is-ready-for-php-8-2 より 18
  6. PHPStan での動的プロパティの検出2 明示的に mixed にしてしまっている場合 class User {} function getUser():

    mixed { return new User(); } $user = getUser(); $user->name = 'udon'; // Cannot access property $name on mixed. 動的プロパティは静的解析で検知できるのか 19
  7. PHPStan での動的プロパティの検出3 プロパティを持たない型が入る可能性がある場合 class User {} function getUser(bool $isUser =

    true): User|string { return $isUser ? new User() : 'string'; } $user = getUser(); $user->name = 'udon'; // Cannot access property $name on string|User. 動的プロパティは静的解析で検知できるのか 20
  8. PHPStan での動的プロパティの検出4 引数の型が不明な場合 function setUserName($user): string { return $user->name =

    'udon'; } // Function setUserName() has parameter $user with no type specified. 動的プロパティは静的解析で検知できるのか 21
  9. Phan での動的プロパティの検出2 少し詳しくみてみたところ、Phan だけで検出できたものには以下のものがありました PHPStan では Access to an undefined

    property ではなく別のエラーとして検 出されているものを拾っていた PhpStorm でなぜか検知できていない型があいまいな変数に対しても検知ができてい た これに関してはもしかしたら PhpStorm が賢すぎるのかも? 動的プロパティは静的解析で検知できるのか 23
  10. Phan での動的プロパティの検出3 親クラスでは定義されていないけど子クラスでは定義されている、みたいないわゆるポリ モーフィックなコードも検知していた class ParentClass {} class ChildClass extends

    ParentClass { public $property = 1; } function getProperty(ParentClass $a) { echo $a->property; } getProperty(new ChildClass()); //will work, since $property is defined in Child getProperty(new ParentClass()); //won't work, since $property is not defined in Parent 動的プロパティは静的解析で検知できるのか https://pleiades.io/help/phpstorm/php-possible-polymorphic-call.html より 24
  11. ウチらについて サイボウズで Garoon というグループウェアの開発をやっています PHP 4 の時代から20年以上続くレガシー由緒正しいプロダクトです♡ PHP 8.0 のときの比較演算子の挙動変更でもとっても苦労しました

    興味ある方はこちらの発表をご覧ください 20年ものの巨大レガシープロダクトをPHP 8.0にアップデートした 際の対策と得られた知見 by 赤間 仁志 https://fortee.jp/phpcon-2022/proposal/8f29f20e-1275- 49eb-89c0-fe684e28d110 動的プロパティをどう修正していくか -ウチらの場合- 27
  12. 動的プロパティ撲滅計画 PHP 8.2 リリースまでにやること(もうやった) 静的解析でどれくらい動的プロパティが使われているのか観測する エラーハンドラで動的プロパティの E_DEPRECATED をキャッチして握りつぶす コーディング規約の修正 &

    composer ライブラリのアップデート PHP 9.0 リリースまでにやること(これからやる) 静的解析の結果からわかった動的プロパティの出現箇所をひとつずつ修正する エラーハンドラでキャッチした動的プロパティをログに出し、修正する 動的プロパティをどう修正していくか -ウチらの場合- 28
  13. 静的解析してみた結果 めっちゃ動的プロパティ使ってました PHPStan の Access to an undefined property だけで

    500件くらい Phan の PhanUndeclaredProperty も 500件くらい 重複もあるけど片方しか検知していない箇所もある これ全部を PHP 8.2 リリースまでに修正はできない、と判断し、 PHP 8.2 リリースを優先してリリース後に修正する方針にしました 無理しなくてえらい 動的プロパティをどう修正していくか -ウチらの場合- 29
  14. コーディング規約の修正 PhpStorm の言語レベルを 8.2 にしておけば叱ってくれますが、念の為社 内のコーディング規約も修正して全体にお知らせしておきました composer ライブラリのアップデート 使用しているライブラリの現行バージョンが PHP

    8.2 に対応しているか調 査 対応していない場合はライブラリをバージョンアップ 一部対応しているかわからなかったライブラリについては個別調査 動的プロパティをどう修正していくか -ウチらの場合- 31
  15. 未定義の変数の使用 Undefined Variable Error Promotion var_dump($undefined); // PHP 9.0: Throws

    Error exception. if ($user->admin) { $restricted = false; } if ($restricted) { die('You do not have permission to be here'); } (おまけ)PHP 9 で例外になる愉快な仲間たち https://wiki.php.net/rfc/undefined_variable_error_promotion より 39
  16. 未定義のプロパティの使用 Undefined Property Error Promotion class User {} $user =

    new User(); var_dump($user->name); // PHP 9.0 : Throws Error exception. // プロパティの有無は isset や empty で検知する if (isset($obj->name)) { echo "Hello " . $obj->name; } (おまけ)PHP 9 で例外になる愉快な仲間たち https://wiki.php.net/rfc/undefined_property_error_promotion より 40
  17. 文字列内での変数展開の文法の削除 Deprecate ${} string interpolation $foo = 'value'; $bar =

    'foo'; var_dump( "$foo", // value "{$foo}", // value "{${$bar}}", // value "${foo}", // value PHP 9.0 : Throws Error exception. "${$bar}", // value PHP 9.0 : Throws Error exception. ); (おまけ)PHP 9 で例外になる愉快な仲間たち https://wiki.php.net/rfc/deprecate_dollar_brace_string_interpolation および https://qiita.com/rana_kualu/items/fc4b02e2daaf102aa92f より 41
  18. メソッド引数の暗黙のデフォルトnull値 Deprecate implicitly nullable parameter types function foo(T $var =

    null) {} // PHP 8.4: Deprecated: Implicitly marking parameter $var as nullable is deprecated, // the explicit nullable type must be used instead // PHP 9: remove support for implicitly nullable types in PHP 9 // こうやって書く function foo(?T $var = null) {} function foo(T|null $var = null) {} (おまけ)PHP 9 で例外になる愉快な仲間たち https://wiki.php.net/rfc/deprecate-implicitly-nullable-types より 42