Skip to content

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

公開日:

兵庫県神戸市で開催された『PHP勉強会 in 神戸』でライトニングトーク(5分)として発表しました。

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.

動的に生成されるファイルを

file_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

この関数がfalseを返すことはない… たぶん…おそらく… きっと…

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

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

Page 20

<?php

$vが絶対にfalseになっていないことをアサーション(表明)

$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. ところで file_get_contents()

ほんとにほんとにfalse返すの?

Page 23

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

Q. 実行時のハンドラー設定に

依存する

Page 24

Page 25

Page 26

Page 27

Page 28

Page 29

状況整理

どういう状況が考えられるか

一度確認してみましょう

Page 30

file_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を使わないでね!