Skip to content

“慈悲深いユニオン”とは何か

公開日:

Download PDF

スライドテキスト

Page 1

“慈悲深いユニオン”とは何か

What's benevolent union?

pixiv Inc.
USAMI Kenta

PHP勉強会 in 神戸

2024-07-19 #関ガレ

Page 2

お前誰よ

  • うさみけんた (@tadsan) / Zonu.EXE / にゃんだーすわん
  • ピクシブ株式会社 pixiv事業本部 Webエンジニアリングチーム PHPer
    • 2012年末から現職、APIとかCIとかいろいろなところを見つめてきました
    • 最近はピクシブ百科事典(dic.pixiv.net)も開発しています
  • Emacs PHP Modeを開発しています (2017年-)
  • プログラミング言語にちょっとこだわりのある素人 (spcamp2010)

Page 3

最近のプログラミング言語っぽい発表

  • 「コードを自在に操るためのPHP文法入門」
    (2月 PHPカンファレンス関西2024)
  • 「こんな静的解析導入は負けフラグ」 (3月 PHPerKaigi)
  • 「動的言語型付けバトル」 (3月 PHPerKaigi)

Page 4

さてみなさん

Now, everyone

Page 5

静的解析は
好きですか?

Do you like static
type analysis?

Page 6

<?php

$v = [1, 2, 3];
echo json_decode($v);

Page 7

<?php

$v = [1, 2, 3];
echo json_decode($v);

Page 8

<?php

$v = [1, 2, 3];
echo json_encode($v);

Page 9

<?php

$v = '[1, 2, 3]';
var_dump(json_decode($v));

Page 10

静的型検査万歳

型チェッカーは常に愚かな我々に
先んじてプログラムのミスを
指摘してくれる… そうですよね?

Page 11

次のスライドのコードは
どうでしょうか?

Page 12

<?php

$v = file_get_contents( );

'data.json'

var_dump(json_decode($v));

Page 13

<?php

$v = file_get_contents( );

'data.json'

var_dump(json_decode($v));

Page 14

Page 15

なんでfalse??

どうしてこの関数は失敗したら falseを返すのはなんで???

Page 16

デプロイのミス

A-1.
要求されたファイルが
正しく配置されなかった

Page 17

ファイルの存在
チェックしてない

A-2.
動的に生成されるファイルを
!le_exists()でチェックせずに
アクセスしてしまった この手法は潜在的なリスクがある…

Page 18

<?php

if (!file_exists('data.json')) {
return;
}

// maybe safe
$v = file_get_contents('data.json');
var_dump(json_decode($v));

Page 19

<?php

if (!file_exists('data.json')) {

この関数がfalseを返すこ
とはない… たぶん…

return;

おそらく… きっと…

}

// maybe safe?
$v = file_get_contents('data.json');
var_dump(json_decode($v));

Page 20

$vが絶対にfalseに なっていないことを

<?php

アサーション(表明)

$v = file_get_contents('data.json');

assert($v !== false);
var_dump(json_decode($v));

Page 21

実際にはfalseが返って

<?php

くる可能性を見て見ぬふり

/** @var string */
$v = file_get_contents('data.json');

var_dump(json_decode($v));

Page 22

ほんとにfalse返すの?

Q. ところで !le_get_contents()
ほんとにほんとにfalse返すの?

Page 23

実行時のハンドラー
設定に依存する

Q. 実行時のハンドラー設定に
依存する

Page 24

Page 25

Page 26

Page 27

Page 28

Page 29

状況整理

どういう状況が考えられるか
一度確認してみましょう

Page 30

Gle_get_contents() が返すのは...

  • error_reporting(0) 設定のとき…
    • 関数は常に string と false のどちらも返す可能性がある
    • PHPの既定の振る舞いではファイルが読み込めなくても停止しない
  • ハンドラでエラーをErrorExceptionに変換しているとき…
    • 関数は常に string 値を返す。falseが返ってくることはありえない。
    • 多くのPHPアプリケーションではフレームワークによって設定済み

Page 31

falseが返ってこないなら

<?php

この確認は常に無駄!

$v = file_get_contents('data.json');

assert($v !== false);
var_dump(json_decode($v));

Page 32

本題

ここからがタイトルのネタ

Page 33

“慈悲深いユニオン”とは何か

What's benevolent union?

pixiv Inc.
USAMI Kenta

PHP勉強会 in 神戸

2024-07-19 #関ガレ

Page 34

謎の型

__benevolent<> は
PHPStanに実装された隠し機能

Page 35

functionMap

TypeResolver

Test code

Page 36

なんだこれ?

で、結局なにこれ????

Page 37

Page 38

Page 39

これらの関数の共通点を
探ってみましょう

Page 40

Page 41

Page 42

Page 43

__benevolent<>が使われた関数の共通点は?

  • これらの関数は異常な状態でfalseを返す可能性がある
  • 引数に適切なパラメータを渡して呼び出す限りfalseが返されることはない
    ので、呼び出し後に毎回型検査をするのは不毛
  • PHP 8でfalseを返す代りにErrorがthrowされるようになった

Page 44

__benevolent<>って
結局どう動くの?

Page 45

Page 46

この型を使えば標準関数を
使いやすくするラッパーも作れる

Page 47

Page 48

便利っぽい…?
んだけど、使わないでね!

Page 49

benevolent unionを濫用するな

  • この型は、例外的な状態でfalseを返すまれなケースを表現するのに役立つ
    • その関数が間違った前提条件で呼び出された場合は、false を返す代わり
      に例外を発生させ、呼び出しコードを修正する。
    • その他の例外的な状況では、例外をスローして呼び出し元に処理させるべ
      き。Javaのチェック例外みたいに。

Page 50

安全性を保ち
コードの繰り返しを防ぐには?

Page 51

Page 52

Page 53

Page 54

この関数はFileSystemExceptionをthrowsする

Page 55

PhpStormはハンドリングしない例外を警告する

Page 56

Page 57

benevolent unionよりも
構造化された例外を!!

Page 58

みんなのコードでは
benevolent unionsを
使わないでね!