なぜ、phpのmbstring.func_overloadをdeprecatedにするのに5年かかったのか? -...
TRANSCRIPT
なぜ、 PHP の mbstring.func_overloadを deprecated にするのに 5 年かかったのか? - 慢心、環境の違い
Y8 2017 spring in Shibuya
sasezakiMay 27, 2017
2
目次● 自己紹介● PHP のこれまで● PHP の仕組み と 拡張モジュール● PHP と 文字列● mbstring.func_overload の機能について● 非推奨提案するに至った経緯 / 提案以降の話● 5 年かけたことについての反省点● "mbstring.func_overload" と同じ事態を避けるには● まとめ● ... おまけの話 ( 例えば文字列を避ける、 7.2 での他の deprecated)
3
自己紹介
はじめまして! sasezaki です。 私が mbstring.func_overload について deprecated を表示するようにしろ !と bugs.php.net に issue レポート(#65785) した人です。
4
過去の主な Talk
2009 / PHP 勉強会
PHP カンファレンス 2011
PHP カンファレンス福岡 2016
5
PHP のこれまで
6
皆さん PHP を知っていますか?
7
8
私は
「俺 ホントはPHP のこと、ちっとも 分かってあげてやれてなかったんだ !」
というのを10 年ぐらい続けてます。
9
だって、そうですよね。PHP のソースコード・ドキュメントには非常に多くの開発者が、その都度の状況や思惑などをおりまぜながら、PHP は成長してるのだから。 ( 今も! )
10
閑話休題
11
PHP: Hypertext Preprocessor としてよく聞く話
・ LAMP (Linux, Apache, MySQL, P** ) の P として普及
・ C によく似た文法。グルー言語としてみなされることもある
・ 非常に多くの機能( 拡張 / 関数・クラス ) が標準で 用意されている。
12
PHP これまでの歩み
https://github.com/open-source-museum/the-history-of-php/
13
PHP の普及期 .php3 拡張子? Zend Engine 1 デフォルトでは、 register_globals をオフに - 4.2 stream (I/O抽象化レイヤー ) の導入 - 4.3
1999 2003~
14
PHP 3 や 4 の初期 、みんなmbstring を使っていたかというと・・・
➔ PHP 版の jcode もありましたが・・・➔ ※ PHP 3の頃は、前身として I18n Package というものだったようです。(ext/mbstring/README_PHP3-i18n-ja)
1999 2003~
15
PHP 5移行期● 日本にとどまらず、勉強会やカンファレンスが活発に● “ フルスタックフレームワーク”ブームもありオブジェクト指向が意識されるように
なぜフルスタックを重宝した ? (依存性 ? PHP 4/5バージョンの差異への対応 ?)
● PHP 5.3リリースまで間が空く
2004 2008~
16
さよなら PHP 6● 5.3 リリース
● register_globals , safe_mode, magic_quotes_gpc の非推奨化 (E_DEPRECATED エラー )
● バイナリセーフではない関数 (ereg, split)の非推奨化● GitHub の浸透も相まって ライブラリなど PHP でも開発が活発に / CIの SaaS 台頭
2009 2012~
17
~~ PHP 5.6 そして PHP 7.0, 7.1 ~● 5.5 - preg_replace() の /e 修飾子 (eval)が非推奨に● 5.6 - iconvおよび mbstring の、エンコーディングに関するオプションが非推奨に
● PHP 7.0 リリース● スカラー型宣言 / 戻り値の型宣言 の導入● AST 導入
2013 2017~
18
PHP 7.2 ~● 7.2
● 非推奨の追加– $php_errormsg, create_function(), mbstring.func_overload など
● 8.0● 2020 年 ?● JIT ?
2017~
https://wiki.php.net/todo/php72#timetable
19
PHP のこれまで新規機能を取り込みながらも、危ない機能については廃止しながら進化してきた。
OSS を取り巻く状況の変化により、品質向上の土壌も進化していった。
20
PHP の 仕組み と 拡張モジュール
21
PHP -リクエストごとのライフサイクル
https://www.slideshare.net/ircmaxell/php-under-the-hood-dpc
22
拡張モジュールでの処理のフックMINIT/ MSHUTDOWN
http://fntlnz.github.io/php-extensions-development
23
PHP 拡張 の 種類
http://php.net/extensions.membership
24
コア拡張
● ストリーム (4.3 にて登場 )● Phar (5.3から組み込み )● SPL (5.3から組み込み )
・・・など今となっては、当然存在するでしょ !
という機能も、過去にはビルド時に外せた
「これらは実際のところ拡張ではありません。 PHPのコアに組み込まれており、 コンパイルオプションで無効にすることはできません。」
http://php.net/extensions.membership
25
バンドルされている拡張
● iconv● マルチバイト文字列 (mbstring)● intl
・・・など
「これらの拡張は PHP にバンドルされています。」
http://php.net/extensions.membership
26
外部拡張
● 各 DB向けドライバ (MySQLi など )
● Gettext ● DOM● cURL
・・・など
「これらの拡張は PHP にバンドルされていますが、コンパイルするには外部ライブラリが必要となります。」
http://php.net/extensions.membership
27
PECL 拡張
● V8js● SPL_Types / Data Structures● phtreads / 各イベント系 (libevent など )● mysqlnd_* 系
・・・など
ここまでが、 php.net にてマニュアルが閲覧できるものです。
「これらの拡張は » PECL にあります。 また、外部のライブラリを必要とするかもしれません。」
28
その他 ● hnw/php-timecop● krakjoe/autostrict● runkit7/runkit7 (funkit)
・・・など
野良拡張を導入して、今まで動いてたスクリプトが動かない!は自己責任
29
PHP の しくみ / 拡張モジュール
PHP 自体でのフック・コード解析する余地がある。
開発者と利用者 ( コンポーネント開発者 ) が想定する環境はコアとバンドルである。
30
PHP と 文字列
31
「 PHP では、 文字は 1 バイトと同じです。つまり、 256 個の異なる文字を使用可能です。 これは、PHP が Unicode をネイティブにサポートしていないことも意味します。」
http://php.net/language.types.string
32
「 PHP における文字列型は、バイトの配列と整数値 (バッファ長 ) で実装されています。 バイト列を文字列に変換する方法については何の情報も持っておらず、完全にプログラマ任せとなっています。」
http://php.net/language.types.string
33
https://www.slideshare.net/nikita_ppv/php-7-what-changed-internally
PHP 5 での zval
34
https://www.slideshare.net/nikita_ppv/php-7-what-changed-internally
PHP 7 での zval
35
ということは?
36
・・というような例もあります。
37
... あなたの PHP で書かれたプログラムソースではバイナリ操作って行います?(バイナリ操作のために文字列関数使ってますか? )
38
PHP と バイナリ操作と・・● 画像処理 (GD, ImageMagick)
● ファイル判定 (finfo)
● password_hash などの パスワードのハッシュ (5.5)● random_bytes (PHP 7.0)
39
「けど、けど、文字 (テキスト )とバイナリ を分けないと不便じゃん!」
40
もしかして、 PHP 6 の話 ですか?
https://www.slideshare.net/andreizm/the-good-the-bad-and-the-ugly-what-happened-to-unicode-and-php-6
41
PHP での文字エンコーディングモジュール
● iconv● mbstring● intl
42
PHP と 文字列
PHP では低レイヤに関わる機能の多くを提供している。
PHP で 文字エンコーディングに関わる操作を行うときは、専用のモジュールが必要となる。
43
mbstring.func_overload とは
44
「 PHP アプリケーションの多くは、英語等のシングルバイトの言語用に設計されており、 日本語を含むマルチバイト文字列を扱う場合には問題を生じる場合があります。 substr() 等の PHP の文字列関数の多くは、 マルチバイト文字列に対応していません。」
php.net/mbstring.overload
45
なので (?)
46
「 mbstring では、 対応するマルチバイト文字対応版の関数で既存の PHP 関数を オーバーロードする機能をサポートします。関数のオーバーロードを行うと、例えば substr() を PHP スクリプトでコールした場合に、 mb_substr() が代わりにコールされるようになります。 これにより、マルチバイト文字に対応しないアプリケーションの移植が容易となります。」
php.net/mbstring.overload
47
なんと ! 夢のような機能!
48
mbsting.func_overload の対象となる関数
49
動作例
mbstring.internal_encoding = UTF-8mbstring.func_overload = 2
php.ini
sample.php
<?= strlen("あ "); // 1
50
素敵!抱いて!
51
(;´Д`)unexpected.php
<?php$html = '<html>...';
$response->setHeader('Content-Length', strlen($html));
52
mbstring.func_overload はマルチバイトを考慮できてないアプリケーションへの解決案だった。
バイナリと文字に違いがない PHP にとっては、影響の高い機構だった。
mbstring.func_overload とは
53
非推奨と提案するに至った経緯 / 各開発者の反応
54
2012 年
● Zend Framework 2の開発がスタート● Db などのいくつかのコンポーネントのアーキテクチャは書きなおされました。が、あくまでベースは ZF1 。
55
当時の私は、こういう憤りをもってました。
「メジャーバージョンアップに合わせて git に移行したけど、 (1.系からの )枝分かれ以降の修正が取り込まれてないじゃん。ずこ!」
56
プルリク!マージ !貢献 !圧倒的成長 !
57
そんなとき
58
Zend Framework の 開発者ML
2012 年 4月
59
zf1 にて、各コンポーネントごとで PHP 環境の差分対応のために横展開的な修正があったことから、ユーティリティコンポーネント (Zend\Stdlib)
の開発気風が高まり、その一環でマルチバイト対応の点から、StringUtils の提案が行われます。
60
当時の対応
・・・mbstring.func_overload フラグがあったら分岐の繰り返し
61
メイン開発者の一人 Ben Scholzen の投稿
http://zend-framework-community.634137.n4.nabble.com/Environment-amp-StringUtils-td4559272.html
62
mbstring.func_overload で ZF を壊すやつは 他の方法でも環境を壊す(safe_mode をオンにしてるように )
63
かくして、 ZF 2ではmbstring.func_overload をサポートしない方向へ
2012 年 4月
64
僕「分かったっす。僕これ mbstring のメンテナーに伝えるっす」
65
CakePHP や Symfony 、 PEARのライブラリでもフラグによる分岐があることを踏まえて、廃止の提案
66
mbstring メンテナー廣川さんの廃止に向けてのレスポンスあり
67
大垣さんが deprecated の提案を internals に投稿
※ internals とは、 PHP のコア開発についてのメインの ML です。http://news.php.net/php.internals
68
その時 (2012 年 4月 )の反応
> 特になし! <
69
... もちろん この2012 年 4月の時点で「 mbstring.func_overload やめた方が良くない?」が PHP利用者に伝わる訳ではなく。。
70
2012 年 5月
https://github.com/reactphp/react/pull/27
71
ReactPHP でのmbstring.func_overload が
ONのときをサポートしようとするPull Request
2012 年 5月
72
僕「 You 、やめときなよ」
「それでも、動かせるようにしたい」
73
igorwのレスポンス
「 mbstring.func_overload の振る舞いは register_globals や magic quotesへの 汚いハックを思い出させる」
74
~~そのまま時は流れる ~~
75
bugs.php.net に レポート
2013 年 9月
76
2013 年 10月
「ユニコードについてのスライド up しました」、
という PHP 開発者のツイート
https://twitter.com/auroraeosrose/status/388380154713489409
77
`Intl doesn't support function “overloading”`
78
Nikita が 反応
「 func_overload は ASAP な drop対象でしょ」
79
僕「その件なんですけど、 bugs にレポートしてまして・・」
Nikita 「 intenals に投稿して」
80
僕「か、かしこま ! 」
81
~~けど、そのまま時は流れ ~~
PHP 7の開発も佳境に入り
82
Nikita の deprecation の提案
2015 年 3月
83
2015 年 3月
84
~~またまた時は流れ ~~
85
2016 年 2月
7.1 に向け Deprecation の RFC 提案が出されhttp://news.php.net/php.internals/91265
86
2016 年 11月
RFC は 7.2 向けの Deprecations に http://news.php.net/php.internals/96993
87
2016 年 11月
非推奨の一つとして、 mbstring.func_overload がリストに上がる
https://wiki.php.net/rfc/deprecations_php_7_2
88
賛成多数で可決
2017 年 1月
https://wiki.php.net/rfc/deprecations_php_7_2
89
ちなみに
90
2016 年 12月
・・ twig ではしれっと削除されてる
https://github.com/twigphp/Twig/commit/b09faf8
91
非推奨と提案するに至った経緯 / 各開発者の反応
PHP利用者 ( 主にライブラリ作成者 ) は、 PHP が標準で用意しているがために mbstring.func_overload をサポートしようとしていた。
PHP 自体が用意している機能でも見直すことが必要。
92
反省点
93
Zend Framework 2 での ML でのやりとり、および日本人メンテナーへの報告 (2012 年 ) からinternals での投票可決と masterへの反映まで5 年の月日が経過していた。 ※ PHP 7.2 はまだリリースはされていません。
➔なぜ 5 年かけてしまったのか?
➔5 年の歳月のうち取れた行動はなかったのか?
94
● 取れるべきアクションを取らなかった 慢心● 環境の違い を否定できてなかった後悔
95
● レポートは一度どこかに投稿すれば終わりという訳ではない● 動きがなかったら、再度自分からアクションを起こすしかない➔internals や bugs.php.netへの登録はもっと早めにできたはず
取れるべきアクションを取らなかった 慢心
96
取れるべきアクションを取らなかった 慢心● マニュアルに注意書きを載せることも可能だった
● 実は、 php.gr.jpへの投稿時に注意書きも載せた方がいいですね。という話はあった。– コミット権がないことに、人任せになっていた。– マニュアルの警告追記も用意してマージ依頼までもできたはず。
●警告の理由を、皆が納得できるように事細かく書かなればという思いこみもあった。という逃げ
97
環境の違い を 否定 できてなかった後悔● 環境の違いを否定する環境づくり
● ライブラリ導入時のチェックを強化すべきだったのでは– 例 ) mbstring.func_overloadがオンの時にコンポーネントをインストールさせない
● 周知・啓蒙が足りなかった ?
98
ところで
99
「あぁ、 mbstring.func_overload が 邪魔する件?」
「前から知ってたよ。」
100
?
101
2004 年 7月
102
2004 年 7月
* Do not use gzip encoding if certain string functions are overloaded bymbstring extension (bug #1781)
103
実は 13 年ぐらい前から気付いてた。
104
コミュニティ・バグトラッキングの分断という後悔
105
結局、現状の機能を肯定してしまったがために長い間 NO と言えなかった。
盲目的に、臭いものに蓋をするようにコーディングを行っていたのはなぜだろう?
106
慢心・環境の違い
107
"mbstring.func_overload" と同じ事態を避けるには
108
PHP 言語の成長の貢献者としてできること (?)➔傍観者効果に陥らないようにする
– リーナスの法則?
➔先人の教訓を生かす– YAGNI, Feature Creep, 結果の局所化
PHP の利用者としてできること➔ヴァージョン互換性・設定依存と向き合う
109
ヴァージョン互換性・設定依存と向き合う秘伝のタレをやめる
「あらゆる環境での動作サポート」という欲望を捨てる➔PHP 環境の前提条件 (ビルドオプション ・php.ini) を制限する
(PHP のヴァージョンアップに対して )
継続的・横断的に動作することを検証、マイグレーションの促進・いびつな設定の排除➔コード解析、ユニットテスト、互換性の確認
処理のフックでごまかす (?)
110
アプリケーション動作環境の前提条件 を制限する
● 動作時にチェックする ?● 例 ) コンストラクタで extension のチェック
● アプリケーション構築時の前提条件を制限する● プロビジョニングによる冪等性● フレームワークによる環境チェック
(参考例 )SymfonyEnvironments
● コンポーネント・インストール時の前提条件を制限する● Diagnostics● composer だと pre-install-cmd ?
111
PHP でのコード解析 (基本 )
デバッガ・プロファイラ・ユニットテスト Xdebug, phpdbg
静的解析 Reflection tokenizer
PHPParser
AST (nikic/php-ast)
● IDE, SaaS (scrutinizerなど ), 他の言語による解析ツール
112
https://github.com/ziadoz/awesome-php#code-analysis
PHP のコード解析ツールは様々なものが登場しています
113
互換性を確認する
PHP 7 へ非推奨となった箇所の診断 php7cc など
複数の PHPバージョンでの挙動確認 3v4l など
利用しているモジュール・関数の互換性解析● PHP CompatInfo
114
まとめ
115
今日の主な話は
● 歴史のある OSS だからこそ、抱える問題に目を背けていてはいけないという話
● PHP での機能非推奨化への過程の一例紹介● PHP の進化を支えるための基本の紹介
116
● 例えば文字列をさける● PHP 7.2での deprecation
● mbstring.func_overload以外で● PHP 7での文字列最適化
おまけの話
117
● fig/http-messageでのストリームと Content-Length
● 拡張での処理のフック● runkitを用いた処理の書き換え
● 名前空間を使った hack <非推奨 >
● Varを dump すると、ほら・・ <非推奨 >
● 口承伝来 bin2hex との組み合わせ <非推奨 >
例えば文字列をさける
118
※ Wiki.php.net の rfc ページ見ながら話します
PHP 7.2でのdeprecation
119
※資料『 PHP AST 徹底解説 (補遺 )』にて、該当箇所の確認をします
PHP 7での文字列最適化
120
ご清聴ありがとうございました