Skip to content

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

公開日:

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

Download PDFPDF

スライドテキスト

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

"慈悲深いユニオン"とは何か 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

"慈悲深いユニオン"とは何か 24ページ

Page 25

"慈悲深いユニオン"とは何か 25ページ

Page 26

"慈悲深いユニオン"とは何か 26ページ

Page 27

"慈悲深いユニオン"とは何か 27ページ

Page 28

"慈悲深いユニオン"とは何か 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

"慈悲深いユニオン"とは何か 37ページ

Page 38

"慈悲深いユニオン"とは何か 38ページ

Page 39

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

Page 40

"慈悲深いユニオン"とは何か 40ページ

Page 41

"慈悲深いユニオン"とは何か 41ページ

Page 42

"慈悲深いユニオン"とは何か 42ページ

Page 43

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

  • これらの関数は異常な状態でfalseを返す可能性がある
  • 引数に適切なパラメータを渡して呼び出す限りfalseが返されることはない

ので、呼び出し後に毎回型検査をするのは不毛

  • PHP 8でfalseを返す代りにErrorがthrowされるようになった

Page 44

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

Page 45

"慈悲深いユニオン"とは何か 45ページ

Page 46

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

Page 47

"慈悲深いユニオン"とは何か 47ページ

Page 48

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

Page 49

benevolent unionを濫用するな

  • この型は、例外的な状態でfalseを返すまれなケースを表現するのに役立つ
  • その関数が間違った前提条件で呼び出された場合は、false を返す代わり

に例外を発生させ、呼び出しコードを修正する。

  • その他の例外的な状況では、例外をスローして呼び出し元に処理させるべ

き。Javaのチェック例外みたいに。

Page 50

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

Page 51

"慈悲深いユニオン"とは何か 51ページ

Page 52

"慈悲深いユニオン"とは何か 52ページ

Page 53

"慈悲深いユニオン"とは何か 53ページ

Page 54

この関数はFileSystemExceptionをthrowsする

Page 55

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

Page 56

"慈悲深いユニオン"とは何か 56ページ

Page 57

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

Page 58

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