Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
PHP 8 になるまでの sort は相当ヤバい
Search
taisuke arase
September 27, 2024
Technology
0
58
PHP 8 になるまでの sort は相当ヤバい
taisuke arase
September 27, 2024
Tweet
Share
More Decks by taisuke arase
See All by taisuke arase
PHP 9 に備えよ - 動的プロパティ、どうすればいぃ?
taisukearase
0
4.6k
Other Decks in Technology
See All in Technology
SREの視点で考えるSIEM活用術 〜AWS環境でのセキュリティ強化〜
coconala_engineer
1
250
Webアプリを Lambdaで動かすまでに考えること / How to implement monolithic Lambda Web Application
_kensh
7
1.2k
古き良き Laravel のシステムは関数型スタイルでリファクタできるのか
leveragestech
1
630
“パスワードレス認証への道" ユーザー認証の変遷とパスキーの関係
ritou
1
320
大規模サービスにおける カスケード障害
takumiogawa
3
790
Devinで模索する AIファースト開発〜ゼロベースから始めるDevOpsの進化〜
potix2
PRO
6
2.5k
LangfuseでAIエージェントの 可観測性を高めよう!/Enhancing AI Agent Observability with Langfuse!
jnymyk
0
170
Cursor AgentによるパーソナルAIアシスタント育成入門―業務のプロンプト化・MCPの活用
os1ma
8
2k
「それはhowなんよ〜」のガイドライン #orestudy
77web
9
2.4k
テキスト解析で見る PyCon APAC 2025 セッション&スピーカートレンド分析
negi111111
0
270
DuckDB MCPサーバーを使ってAWSコストを分析させてみた / AWS cost analysis with DuckDB MCP server
masahirokawahara
0
450
アプリケーション固有の「ロジックの脆弱性」を防ぐ開発者のためのセキュリティ観点
flatt_security
40
16k
Featured
See All Featured
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
13
1.4k
Automating Front-end Workflow
addyosmani
1369
200k
The World Runs on Bad Software
bkeepers
PRO
67
11k
RailsConf 2023
tenderlove
30
1.1k
Speed Design
sergeychernyshev
29
880
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
280
13k
What’s in a name? Adding method to the madness
productmarketing
PRO
22
3.4k
A Tale of Four Properties
chriscoyier
158
23k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
248
1.3M
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
32
4.9k
What's in a price? How to price your products and services
michaelherold
245
12k
GitHub's CSS Performance
jonrohan
1030
460k
Transcript
PHP 8 になるまでの sort は相当ヤバい 2024.09.28 PHP Conference Okinawa 2024
荒瀬 泰輔 #phpcon_okinawa #track_a
荒瀬 泰輔 @at_taisuke PHPer歴 5年くらい サイボウズかき氷部の部長 2024月刊ぺちこん参加 北海道 東京 香川
福岡 沖縄 2
3
沖縄のおすすめかき氷 4
かんな +plus さん 東京の三宿の人気店「和キッチン かんな」の分店 沖縄ならではの食材を使ったかき 氷 写真は「イエロー」 (パッション フルーツとマンゴーのかき氷)
5
avocafe さん アボカド料理店 クリーミーなアボカドはかき氷 にしても美味しい! 写真は「アボカドキャラメルナッ ツ」 6
行きたいお店 天の群星(てぃんのむりぶし) PLUS MINUS 琉冰( Ryu-Pin) 皆さんのおすすめかき氷、沖縄ぜんざいのお店あったら #phpcon_okinawa で教えてください! 7
本題 8
…の前に 9
[悲報 ] タイトル、半分釣りだった 10
結論 数値と文字列をごちゃ混ぜにした配列を sort しようとしている のがヤバい とはいえ PHP 8 より前の比較演算もヤバいのでどっちもヤバい sort
をするならヤバいコードは掃討しましょう 11
Agenda 当初話す予定だったブログ記事の紹介 x でのご指摘を受けての再調査 PHP の比較の挙動 おまけ PHP の比較 true
or false ? クイズ 「数値から始まる文字列」について 12
当初話す予定だったブログ記事の紹介 13
事前にこの場で話す内容をブログ記事に してました 「 CYBOZU SUMMER BLOG FES '24」 という企画で 8/15
に公開 PHP 8 になるまでの sort は相当ヤバい https://zenn.dev/t_arase/articles/0a12bfd6a76e25 当初話す予定だったブログ記事の紹介 14
PHP 7の比較に矛盾が生じてるぞ! <?php // PHP 7.4.33 var_dump(11 < '12'); //
true var_dump('12' < 'a1'); // true var_dump('a1' < 10); // true var_dump(10 < 11); // true 当初話す予定だったブログ記事の紹介 15
当初話す予定だったブログ記事の紹介 https://commons.wikimedia.org/wiki/File:Impossible_staircase.svg より 16
sort の結果もおかしいぞ! <?php $arr1 = [11, 10, '12', 'a1']; sort($arr1);
var_export($arr1); echo PHP_EOL; $arr2 = ['12', 'a1', 11, 10]; sort($arr2); var_export($arr2); echo PHP_EOL; var_dump($arr1 === $arr2); 当初話す予定だったブログ記事の紹介 17
# PHP 7.4.33 array ( 0 => 10, 1 =>
11, 2 => '12', 3 => 'a1', ) array ( 0 => '12', 1 => 'a1', 2 => 10, 3 => 11, ) bool(false) // var_dump($arr1 === $arr2) 当初話す予定だったブログ記事の紹介 18
PHP 8 でこの矛盾が解消されたぞ! <?php // PHP 8.0.0 var_dump(11 < '12');
// true var_dump('12' < 'a1'); // true var_dump('a1' < 10); // false ここが変わった var_dump(10 < 11); // true 当初話す予定だったブログ記事の紹介 19
PHP 8 で比較演算の挙動が変わったため 数値と「数値形式ではない文字列」を比較する際 PHP 7 まで:文字列を数値に変換してから比較 PHP 8 から:数値を文字列に変換してから比較
するようになった 数値と「数値形式の文字列」を比較する際は今まで通り文字列を数値 に変換してから比較する 'hoge' == 0; // true PHP 7.4.33 まで 'hoge' == 0; // false PHP 8.0.0 から 当初話す予定だったブログ記事の紹介 PHP RFC: Saner string to number comparisons https://wiki.php.net/rfc/string_to_number_comparison より 20
sort 順も正しくなった! // PHP 8.0.0 array ( 0 => 10,
1 => 11, 2 => '12', 3 => 'a1', ) array ( 0 => 10, 1 => 11, 2 => '12', 3 => 'a1', ) bool(true) 当初話す予定だったブログ記事の紹介 21
PHP 8 までの sort は相当おかしい! ヨシ! 当初話す予定だったブログ記事の紹介 22
x でのご指摘を受けての再調査 23
記事公開後、コメントをいただきました 文字列と数値混じりの sortができるように変わったと誤解しそう なので、できない例も載せても良いのではと思いました var_dump(11 < '12'); var_dump('12' < '3a');
var_dump('3a' < '4'); var_dump('4' < 11); x でのご指摘を受けての再調査 ぺん! @tompng さんありがとうございました! https://x.com/at_taisuke/status/1824000184231321736 24
確かに PHP 8 でも比較がおかしいよう な …? // PHP 8.0.0 var_dump(11
< '12'); // true var_dump('12' < '3a'); // true var_dump('3a' < '4'); // true var_dump('4' < 11); // true x でのご指摘を受けての再調査 25
$arr1 = [11, '4', '12', '3a']; sort($arr1); var_export($arr1); $arr2 =
['12', '3a', 11, '4']; sort($arr2); var_export($arr2); var_dump($arr1 === $arr2); array ( 0 => '4', 1 => 11, 2 => '12', 3 => '3a', ) array ( 0 => 11, 1 => '12', 2 => '3a', 3 => '4', ) bool(false) x でのご指摘を受けての再調査 26
自分の遭遇した例がたまたま PHP 8 でいい感じになっただけで、 ダメなパターンもある どうしてこういう結果になるのか再度調査しなくては x でのご指摘を受けての再調査 27
PHP の比較の挙動 28
文字列同士の比較 先頭の文字から順に Unicode 値を使い辞書的に比較する 'a' < 'b'; // true 'a'
< 'A'; // false 'a ' < 'a1' // true PHP の比較の挙動 29
おさらい: PHP 8 での比較で変わった点 数値と「数値形式ではない文字列」を比較する際 PHP 7 まで:文字列を数値に変換してから比較 PHP 8
から:数値を文字列に変換してから比較 するようになった 数値と「数値形式の文字列」を比較する際は今まで通り文字列を数値 に変換してから比較する 'hoge' == 0; // true PHP 7.4.33 まで 'hoge' == 0; // false PHP 8.0.0 から PHP の比較の挙動 30
「数値形式の文字列」について PHP には「数値形式の文字列( numeric strings) 」という概念があ る PHP 7.4.33 までは「
0個以上のスペース + 数値」がこれに該当した が、 PHP 8 からは「 0個以上のスペース + 数値 + 0個以上のスペース」に 変更になった // 数値形式の文字列の例 '11' ' 11 ' // 後ろにスペースがあるため、PHP 8 より前ではただの文字列扱いだった '000011' '11.0' '+11.0E0' PHP の比較の挙動 31
コメントをもらった例を見てみる 11 < '12'; // true // 数値と「数値形式の文字列」の比較のため、「数値形式の文字列」を数値として扱う '12' <
'3a'; // true // 文字列同士の比較となり、最初の1文字目の Unicode で比較される '3a' < '4'; // true // 文字列同士の比較となり、最初の1文字目の Unicode で比較される '4' < 11; // true // 数値と「数値形式の文字列」の比較のため、「数値形式の文字列」を数値として扱う 何と比較されるかで、その値が文字列として扱われるか、数値として 扱われるか変わるため、 sort して順番をつけることができない つまりこんな値を sort しようとするのが悪い PHP の比較の挙動 32
結論 数値と文字列をごちゃ混ぜにした配列を sort しようとしている のがヤバい とはいえ PHP 8 より前の比較演算もヤバいのでどっちもヤバい sort
をするならヤバいコードはそーっとしておかずに掃討しまし ょう 33
ここまで話せたらあとはおまけ 34
PHP の比較 true or false ? クイズ 35
全て PHP 8.0.0 以降の結果で考えてください 全部で 4問です PHP の比較 true or
false ? クイズ 36
10 < 11 true or false ? PHP の比較 true
or false ? クイズ 37
true 数値どうしの比較 10 < 11 PHP の比較 true or false
? クイズ 38
1 < '1 ' true or false ? PHP の比較
true or false ? クイズ 39
false 数値と「数値形式の文字列」の比較のため、 「数値形式の文字列」を 数値として扱う 1 < '1 ' PHP の比較
true or false ? クイズ 40
'1a' < 10 true or false ? PHP の比較 true
or false ? クイズ 41
false 文字列どうしの比較となり、数値を文字列として扱い 1文字目から順 に Unicode で比較される '1a' < 10 ちなみに
PHP 7.4.33 までだと '1a' が数値として扱われ、数値どう しの比較になり、 true になる PHP の比較 true or false ? クイズ 42
'123' < '45 ' true or false ? PHP の比較
true or false ? クイズ 43
false 「数値形式の文字列」どうしの比較になり、両方を数値として扱う '123' < '45 ' ちなみに PHP 7.4.33 までだと
'45 ' が文字列として扱われ、最初 の文字の '1' と '4' の比較の結果、 true になる PHP の比較 true or false ? クイズ 44
「数値から始まる文字列」について 45
「数値から始まる文字列」について PHP には「数値から始まる文字列 (leading-numeric strings)」 という概念も存在する 「数値から始まる文字列」は「数値形式の文字列」 + 任意の文字列 で構成される
'123abc' これは比較演算の際にはただの文字列と同じ扱いになる '123' < '45abc' // true 「数値から始まる文字列」について 46
「数値から始まる文字列」について 「数値から始まる文字列」は数値にキャストした場合には「数値形式 の文字列」部分を数値に変換した値になる var_dump((int) '45abc'); // 45 var_dump((int) 'abc45'); //
0 「数値から始まる文字列」は 数値型が宣言されている引数に入れる ことはできない。 function foo(int $i) { var_dump($i); } foo("123 "); // int(123) foo("123abc"); // TypeError 「数値から始まる文字列」について 47
「数値から始まる文字列」かどうかの見 分け方 「数値から始まる文字列」かどうかは数値に足してみて warning が 出るかどうかで判断できる。 ( PHP 8.3 )
var_dump(123 + "123 "); // int(246) var_dump(123 + "123a"); // Warning: A non-numeric value encountered // int(246) 「数値から始まる文字列」について 48
PHP 7.4.33 までの「数値形式の文字列」 PHP 7.4.33 までは、数値の後ろにスペースがある場合は「数値から 始まる文字列」扱いとなっていた。 // PHP 7.4.33
var_dump(123 + "123 "); // Notice: A non well formed numeric value encountered // int(246) 「数値から始まる文字列」について 49
ご清聴ありがとうございました! 50