web-dev-qa-db-ja.com

PHP Unicodeと互換性がない要因は何ですか?

スクリプトではUTF-8文字を問題なく使用できます。

実際のところ、 変数の名前と関数にUnicode文字が含まれている が可能です。

マルチバイト文字列を扱う mb_string拡張子 もありますが、無数の記事でPHPはUnicodeサポートがないことで批判されています。

わかりません。 PHPはUnicodeをサポートしていないと言われているのはなぜですか?

42
moo

PHPが数年前に開始されたとき、UTF-8は実際にはサポートされていませんでした。Windows98/ Meのような非UnicodeOSがまだ最新であり、他の大きな言語のような時代について話しています。 Delphiも非Unicodeでした。1日目からすべての言語がUnicodeを念頭に置いて設計されたわけではなく、多くのものを壊さずに言語をUnicodeに完全に変更するのは困難です。 JavaやC#のような他の言語は1日目からUnicodeで設計されました。

したがって、PHPが成長してPHP 3、PHP 4そして今はPHP 5、単に誰もUnicodeを追加することを決めませんでした。なぜですか?おそらく既存のスクリプトとの互換性を維持するため、またはutf8_de/encodeとmb_stringがすでに存在して機能しているためです。確かなことはわかりませんが、それはオーガニックと関係があると強く信じています。機能はデフォルトで単に存在するのではなく、誰かが作成する必要があり、それはPHPではまだ発生していません。

編集:わかりました、私は質問を間違って読みました。問題は、文字列はどのように内部に保存されるのかということです。 「Währung」または「Écriture」と入力した場合、使用されるバイトを作成するために使用されるエンコーディングはどれですか? PHPの場合、コードページではASCIIです。つまり、ISO-8859-15を使用して文字列をエンコードし、中国語のコードページでデコードすると、奇妙な結果が得られます。別の方法は、C#やJavaすべてがUnicodeとして保存される言語です。つまり、コードページはもう存在せず、理論的には混乱することはありません。お勧めします Joelの記事 Unicodeと文字セットについてですが、基本的には次のようになります。文字列は内部にどのように格納されますか。PHPは「Unicodeではありません」です。つまり、非常に厳密である必要があります。文字列を処理するときは注意深く明示的に、入力、保存(データベース)、および出力中に文字列を常に適切なエンコーディングに保つようにしてください。これは非常にエラーが発生しやすいものです。

45
Michael Stum

技術的な問題ではなく、主に文化的な問題だと思います。

技術的な問題については---そして、「1文字が1バイトに等しい」という仮定に基づいて構築されたエコシステムにUnicodeを実装するのは簡単ではありません---開発者はJavaまたはPythonの努力の多くをコピーできたはずです(後者2001年頃から、まともで大部分が機能するUnicode互換性を備えています)が、実際にはそうではありませんでした。

phpのutf8_encode() functionの公式の最新ドキュメントに添付されているディスカッションスレッド を読むと、めまいを感じます。

まず、その関数はutf8_encode()と呼ばれます。ただし、ドキュメントには、予期される文字列はISO-8859-1(別名latin-1)であると予想されると記載されています。それはすっごくphpです、それはすっごく80年代です。

ほとんどのコメント提供者は、Unicodeを負担として認識しているようです。 「未知のコンテンツの文字列」を変換する方法、「混合エンコーディングの文字列」(wtf?)を処理する方法、または関数の4バイト/バイトを超えているために通常は破損を引き起こすコードポイントを処理する方法については、多くの提案があります。コードポイント制限。

議論は、波線を取り除くため、またはその関数の動作の問題のある部分を回避するための修正を中心に行われます。そして、それは私にとってはすごいphpです。誰もが修正を行っているだけで、根本的に正しい方法で実装されているものはほとんどありません。これが私の側の誹謗中傷であると信じている場合は、ここにいくつかのヒントがあります。

ドキュメントがすでにUTF-8である場合、これはドイツ語のウムラウト[äöü]を壊すようですが。

(utf-8が2回適用されたときに機能するように設計されていないことを理解できませんでした)

8859と恐ろしい1252からUTF8に変換する方法を提供するiconv()関数を見てください。

(良い点:php開発者の一部での先行技術の無視;代わりに、バグのある独自の実装)

preg_matchを使用してutf8_encodeが必要かどうかを検出する[...]サロゲートを除外する[...]オーバーロングを除外する

(文字列から問題のあるすべてのコンテンツをサイレントに消去し、utf8_encode()を壊さないものだけを残すことをお勧めします。これにより、テキストが読めなくなる(または完全に消える)可能性がありますが、エラーメッセージはもうありません)

文字列がまだUTF-8でない場合にのみ文字列をエンコードする[...] mb_detect_encoding($s, "UTF-8")

(指摘されているように 別のコメント投稿者による 、これは機能しません:

_$str = 'áéóú'; // ISO-8859-1
mb_detect_encoding($str, 'UTF-8'); // 'UTF-8'
mb_detect_encoding($str, 'UTF-8', true); // false
_

したがって、ここでは、あるバグが別のバグに置き換えられていることを確認しています。幸せな狩猟。また、彼らがここで提案しているように見えるのは、ヒューリスティック(遅い、不確実)手段を使用して問題を解決することです。

utf8utf8_encode()関数がコードポイントあたり4バイトを超えて放棄するだけでなく、結果として(または出力?)テキストが5000文字の制限を超えています)

私はこのように何度も続けることができました。あなたはすでに考えを理解しています:このスレッドから判断すると、phpコミュニティは、エンコーディングと文字セットが何であるか、一般的にサウンドインフラストラクチャを構築するために何が必要か、具体的には何を理解する準備ができているようには聞こえません適切な方法でユニコードを実装します。代わりに、彼らは足場、段ボール、釘、ハンマーを使用して、phpと呼ばれるこの壮大な建物を建設し続け、別の釘では元に戻せないすべての問題にダクトテープを投げます。もちろん、その建物は、時折合法であるが予期しない性格など、吹くあらゆる風に苦しむでしょう。

この特定のスレッドが8年間アクティブであるのを見ても、状況が今から8年間でさらに良くなるという確信を正確に植え付けることはできません。

36
flow

「マルチバイト文字」の概念が問題の核心です。

  1. 実装の詳細がリークされます。実装者がデータの表現をどのように選択するかを知らなくても、文字の抽象化を処理できるはずです。プラットフォームによっては、すべてをUTF16またはUTF32として表現するのに適している場合があります。この場合、すべてがマルチバイト。文字抽象化のユーザーが気にする必要はありません。
  2. 文字列がバイトシーケンスであることを私たち全員が「本当に知っている」という時代遅れの考え方に加えて、バイトがUnicode文字と呼ばれるものに凝集し、特別なものがあることを知る必要があります。それに対処するために至る所でケース。
  3. まるでネズミが象を食べようとしているようなものです。 UnicodeをASCII(通常の文字列とmb_strings)の拡張としてフレーミングすることにより、問題が発生し、文字を処理するために必要な特殊なケースに悩まされます。複数のバイトを必要とする面白い波線。Unicodeを必要な文字に抽象的なスペースを提供するものとして扱う場合、ASCIIは、特別な場合として扱う必要なしにそれに対応します。
11
user8599

あなたはそれを自分で言います:マルチバイト文字を含む文字列を正しく処理するために、あなたは拡張子を使う必要があります。使い慣れた「通常の」関数の代わりに拡張関数を使用する場所を忘れると、データが切断されます。どこでも拡張機能を使用するように更新されていないサードパーティのライブラリを使用する場合も同じことが起こります。

また、多くの 非常に人気のあるエンコーディング はまだ明示的にサポートされていませんおそらくそうして滞在することは不可能であるためです下位互換性があります。

5

一般的な拡張機能の多くはUnicodeをサポートしていないか、(さらに悪いことに)XMLReaderなどの文字列にUnicode/utf-8シーケンスが含まれていることを「知る必要があります」。また、PHPのglob()がwin32でFindFirstFileAまたはFindFirstFileWを呼び出すかどうかによって大きな違いが生じる可能性があります。
もう1つの(はるかに小さいが、驚くほど多くの場合、煩わしさの原因となる)問題は、PHPが認識しないBOMです。

3
VolkerK

文字列関数の多くは、Cライブラリに相当するものの単なる薄いラッパーであり、すべてをバイトのシーケンスとして扱います。もう1つの理由は、PHPは、多くの不要な下位互換性のある手荷物を持ち歩くため、3&4からの不適切な設計上の決定に行き詰まっていることです。

たぶん5.3の名前空間で、彼らはついに古い関数を段階的に廃止する方法を手に入れるでしょう。

3
user42092

「サポート」とは「ネイティブサポート」の意味です。詳細情報を入手するには、 this を参照してください。

2
muratgu