ホームページ  >  記事  >  バックエンド開発  >  PHPのダメ設計を5つの側面から徹底分析_PHPチュートリアル

PHPのダメ設計を5つの側面から徹底分析_PHPチュートリアル

WBOY
WBOYオリジナル
2016-07-20 10:58:18703ブラウズ

翻訳者注: この記事は非常に長く、読みにくく理解しにくいかもしれません

前書き

私は、ほとんどのテクノロジーについて不平を言う奇妙な気質を持っています。 PHP は使いにくいだけでなく、私が望むものには適さないし、最も満足できるものでもないし、私が信じているものに反するものでもあります。私が言える言語はこれだけです。良い方法も、私が好む悪い方法もすべて、質問してください。言語、フレームワーク、エコシステム全体を含む、php が唯一の例外です。 php の苦情の複雑なリストを編集しようとするたびに、掘り下げれば調べるほど、それがさらに増えてしまうので、悪口だけを列挙するのは非常に面倒です。他にも衝撃的なことを発見しました。

php はとても壊れていますが、それを褒めるように訓練されているアマチュアには何の関係もありません。しかし、私はそれを忘れることにしました。でも、私は自分のシステムからこれらのものを取り除かなければなりません、それだけです、これが私の最後の試みです

比喩的に言うと

私は何気なくメルに苦情を言っただけですが、彼女はそれを公開するように主張しました。

私はそれを公開することができます。 PHP で何が起こっているのかさえわかりません。だって、大丈夫です。たくさんのツールボックスがあると考えてください。見た目は大丈夫です。ネジを 3 つ取り出します。わかりました、これはあなたにとってはあまり役に立ちませんが、遅かれ早かれ役に立つでしょう。あなたはハンマーを取り出し、両側に鋭い爪がありました。それでも機能します。つまり、両端の真ん中で斜めに叩くことができます

万力を取り出しますが、表面は平らで滑らかです。あまり便利ではありませんが、それでも機能します。大したことはありません

続けてください。工具箱の中身はどれも奇妙で疑わしいものですが、全体的には何も問題はありません。大工さんがたくさんいると想像してください。これらの道具を使って、彼らはあなたにこう言います。「この道具のどこが間違っているのですか?私たちは皆、それらを使ってきましたが、どれもうまくいきました!」 職人たちは、それぞれのドアが五角形で、屋根が平らである家を見せます。玄関のドアをノックすると、ドアが中に落ちてしまい、ドアが壊れてしまったと文句を言われます

それが言語の生産性と使いやすさにとって重要だと思います。は重要であり、PHP はそれらを大幅に破ります。もしあなたがそれらに同意しないなら、私は決して同意することはできないでしょう

>> それはそうです。人間の考えをコンピューターの実行に反映する媒体であるため、重要なのは、人間のプログラムの理解が正しくなければならないということです。同じものは似ていて、異なるものは異なっていなければなりません。言語の一部を学習すれば、残りの部分は簡単に理解できるはずです

>> 新しい言語は、古い言語から受け継いだ悪い形式を減らす必要があります。 ) 新しい言語は、新しい特有の形式を織り込むことを避けるように努めるべきです

>> 言語は、問題を解決するためのツールである必要があります。あらゆる「トラップ」は非常に邪魔になります

>> 何か問題が発生した場合、プログラマはそれを修正する必要があり、私たちは必要な支援を得る必要があります。

>> どこでも驚くべき PHP: mysql_real_escape_string、E_ACTUALLY_ALL

>> PHP には特別な形式が必要です: C API 呼び出しに関するエラーチェック、===

>> PHP は奇妙です: ==. for($foo as &$bar)

>> PHP は不明瞭です: デフォルトではスタック トレースも致命的エラーも報告されません

一言では説明できませんなぜこれらのクラスに分類されるのかを疑問に思ってください。そうでなければ、読者は自分で考えてくれるでしょう。

この件についてはもう私と話さないでください

私は多くの好意的な議論も聞いています。これらは会話をすぐに止めることしかできません。この件について私に話すのはやめてください:(

>> 「良い開発者はどんな言語でも良いコードを書ける」とか、悪い開発者は言わないでください。なんというか、これは意味がありません。優れた職人は釘を打つのに石やハンマーを使うことができますが、石を使う職人を何人見たことがありますか? 優れた開発者の条件の 1 つは、ツールの選択が上手であることです。

>> 言わせてください、何千もの例外や癖を記憶するのは開発者の仕事です。コンピューターは愚かなので、これはシステムが受け入れることができるという意味ではありません。 PHP には異常が伴いますが、言語に慣れてしまうと、実際にプログラムを作成するのに多くの労力がかかります。私のツールはアプリケーションの作成に良い影響を与えません。

>> 「これが C API の仕組みだ」とは言わないでください。提供できるのはいくつかの文字列ヘルパーと多数の C ラッパーだけであるのに、この地球上での高級言語の目的は何でしょうか。 ? もしそうなら、C を使ってください! ここには、CGI ライブラリも用意されています。>> 2 つの機能がある場合は、いつの日か、誰かがそれらを一緒に使用する理由を見つけるでしょう。これは C ではありません。ここには「未定義の動作」は必要ありません

>>それと、Wikipedia PHP は、Brainfuck で書くこともできますが、十分に賢く、これらをいじくり続ける限り、他の言語で書かれていれば、いつでもプラットフォームの問題を克服できます。開発時間は半分または 2 倍に短縮される可能性があります。このデータだけを取り出しても意味がありません。ここに挙げた内容があなたの PHP の観点に悪影響を及ぼさないのなら、これ以上私と議論しないでください。それは問題ではないので、オンラインで無意味な議論をするのはやめてください。私が間違っていることを証明するために、クールでハンサムなサイトを開発し続けてください:)

こっそり伝えてください: 私は Python がとても好きです。聞きたくないです、本当に聞きたければ聞きません。完璧である必要はありません。長所を活かして短所を避け、自分が望む最高のものを要約したいだけです。

PHP

CPAN は「Perl の標準ライブラリ」と呼ばれています。このライブラリには説明が足りませんが、強力なコアがあれば強力なものを構築できるという考えが具体化されています。原則

PHP はもともと非プログラマー向けに設計されています (暗黙的に、非専門的なプログラム)。PHP 2.0 ドキュメントから抜粋したダイアログから抜け出すのはすでに困難です。たとえば、文字列に「==」を使用することはできず、「eq」を使用する必要があります。これは、特に PHP のようなスクリプト言語ではわかりません。ほとんどの場合、非常に単純であり、プログラマーではない人は、多くの学習曲線を費やすことなく、論理構文を備えたいくつかの基本的な言語を必要とするだけです。 > PHP は、どんな犠牲を払っても進歩し続けます。

>> これは、Perl の影響を受けた、C 言語を使用する正しい設計原則ではありません。 ; OO の部分は C++ や Java のように設計されています。

>> PHP は他の言語から多くのインスピレーションを得ていますが、他の言語に慣れている人にとっては、(int) は C のように見えますが、 int は存在​​しません。新しい配列構文は [key => value] を使用します。これは、他の言語のハッシュ リテラルの定義方法とは異なります。

> ;> mumbers/etc.) は非常に複雑です

>> 少数の新機能は新しい構文で実装されます。これには、クラスのサポートに加えて、新しい機能が必要です。演算子とキーワード

>> このページにリストされている問題にはすべて公式の解決策があります。問題を修正するために Zend のオープンソース プログラミングに資金を提供したい場合は、言語について話します。

>> PHP ドキュメントのどこかから抜粋した次のコードを考えてみましょう。

>> PHP が disable-url-fopen-wrapper を使用してコンパイルすると、実行されません。 (ドキュメントには、「動作しない」とはどういう意味か、null を返す、例外をスローする、とは書かれていません)

>> これは PHP 5.2.5 で実装されていることに注意してください

> php.ini でallow_url_fopen が無効になっている場合も機能しません (なぜですか? 知る方法がありません。)

>> @ により、存在しないファイルの警告は表示されません。 .enabled が php.ini に設定されている場合は、再度出力されます。

>> または、ini_set でcreamy.enabled が手動で設定されている場合。

>> ただし、error_reporting レベルが設定されていない場合、

>> 出力される場合、正確な宛先は php.ini または ini_set に依存します。

コンパイルを見ないと、この関数の動作はわかりません。 -time フラグ、サーバー側の構成、およびプログラム内の構成はすべて組み込みの動作です

>> 言語には、func_get_arg のグローバル文字エンコーディングが使用されます。通常の関数と同様ですが、エラー/例外処理はデフォルトでグローバルに設定され、各ティック (フック?) で実行されます。 (上記のとおり、当然のことですが) これは、組み込みフォーク (後述) の欠如と相まって、PHP の特定の側面を非常に困難にします。実際にはエラー コードが生成されます

>> json_decode は、間違った入力に対して null を返しますが、null は JSON デコードの正当なオブジェクトでもあります。この関数は、使用するたびに json_last_error を呼び出さない限り、非常に信頼性が低くなります。

>> 如果在位置0处找到, array_search , strpos, 和其它类似的函数返回0, 但如果都没有找到的话. 会返回 false

让我们稍稍展开最后一部分.

在C中, 函数如 strpos 返回 -1, 如果未找到. 如果你没检查这种情况, 却试着以下标使用它, 那將可能命中垃圾内存, 程序会崩溃. (也许吧, 这是C. 谁泥马知道. 我确定至少有工具处理它)

话说, Python中, 等效的 .index 方法將抛出一个异常, 如果元素没找到的话. 如果你不检查该情形, 程序將崩溃.

在PHP中, 该函数返回 false. 如果你把 FALSE 作为下标使用, 或者用它做其他事情, PHP会默默的將它转成0, 但除了用于 === 比较. 程序是不会崩溃的; 它將执行错误的逻辑, 且无任何警告, 除非你记得在每个使用 strpos 和其它类似函数的地方包含正确的样版处理代码.

这真是糟透了! 编程语言只是工具; 它们是为我服务的. 这里, PHP给我布下了陷阱, 等着我跳进去, 而我不得不时刻警惕这些无聊的字符串操作和相等比较. PHP是个雷区.

我已经听过很多关于PHP解析器的故事, 它的开发者来自世界各地. 有从事PHP核心开发工作的人, 有调试PHP核心的人, 也有和核心开发者交流过的人. 没有一个故事是赞赏的.

因此不得不在这里插入一句, 因为它值得重复: PHP是个业余爱好者的社区. 极少数人设计, 为它工作, 或极少有人知道他们在做什么. (哦, 亲爱的读者, 你当然是个极品例外!) 那些成长了, 想转投其它平台的人, 使整个社区的平均水平下降. 这个, 就是这里, 是PHP的最大问题: 绝对的盲目领导盲目.

好了, 回来面对现实吧.

操作符

== 不中用.

>> "foo" == TRUE , 和 "foo" == 0... 但, 当然 TRUE != 0.

>> == 会將两边转成数字, 如果可能的话, 这意味着它將转成 floats 如果可能. 所以大的16进制字符串(如, password hashes) 可能偶然会比较成 true , 尽管它们不一样. 就连 JavaScript 都不会这样做.

>> 由于某些原因, "6" == "6", "4.2" == "4.20", 和 "133" == "0133". 但注意 133 != 0133, 因为 0133 是八进制的.

>> === 比较值和类型... 除了对象, 只有两边实际上是同一对象才为 true ! 对于对象, == 比较值(或每个属性)和类型, 这又是 === 比较任何非对象类型的行为. 好玩吗?

比较大小也好不到哪去.

>> 甚至行为都不一致: NULL < -1, 而 NULL == 0. 排序也因此不确定; 它依赖于在排序中比较元素的算法的顺序.

>> 比较操作符尝试排序数组, 以两种不同的方式: 首先按长度, 然后按元素. 如果它们有相同数量的元素但不同的keys, 它们是不可比的.

>> 对象比较比其它比较做得更多... 除了那些即不小于也不大于的对象.

>> 为了类型更安全的 == 比较, 我们有 ===. 为了类型更安全的 < 比较, 我们有... 什么也没有. "123" < "0124", 通常, 不管你怎么做. 类型转换也无济于事.

>> 尽管上面的举动很疯狂, 但却明确拒绝Perl's的字符串 paris 和算术运行符, PHP没有重载 +. + 就是通常的 +, 而 . 是通常的连接符.

>> [] 下标操作符也可以拼写成 {}.

>> [] 可以用于任何变量, 不光是字符串和数组. 它返回 null , 无错误警告.

>> [] 仅能获取单个元素.

>> foo()[0] 是个语法错误. (已在 PHP 5.4 中修复)

>> 不像(从字面上看)任何其它语言都有的类似的操作符, ?: 是左结合的. 因此:

<ol class="dp-c">
<li class="alt"><span><span class="vars">$arg</span><span> = </span><span class="string">'T'</span><span>;  </span></span></li>
<li><span> </span></li>
<li class="alt">
<span class="vars">$vehicle</span><span> = ( ( </span><span class="vars">$arg</span><span> == </span><span class="string">'B'</span><span> ) ? </span><span class="string">'bus'</span><span> :  </span>
</li>
<li class="alt">
<span>             ( </span><span class="vars">$arg</span><span> == </span><span class="string">'A'</span><span> ) ? </span><span class="string">'airplane'</span><span> :  </span>
</li>
<li class="alt">
<span>             ( </span><span class="vars">$arg</span><span> == </span><span class="string">'T'</span><span> ) ? </span><span class="string">'train'</span><span> :  </span>
</li>
<li class="alt">
<span>             ( </span><span class="vars">$arg</span><span> == </span><span class="string">'C'</span><span> ) ? </span><span class="string">'car'</span><span> :  </span>
</li>
<li class="alt">
<span>             ( </span><span class="vars">$arg</span><span> == </span><span class="string">'H'</span><span> ) ? </span><span class="string">'horse'</span><span> :  </span>
</li>
<li class="alt">
<span>             </span><span class="string">'feet'</span><span> );  </span>
</li>
<li class="alt">
<span class="func">echo</span><span> </span><span class="vars">$vehicle</span><span>; </span>
</li>
</ol>

打印 horse.

变量

>> 无法声明变量. 当第一次使用时, 不存在的变量会被创建为 null 值.

>> 全局变量在使用前, 需要 global 声明. 这是根据上面得出的自然结果, 因此这是个完美的理由, 但, 如果没有显示的声明, 全局变量甚至无法读取 -- PHP 將悄悄的创建一个局部同名变量取代它. 我还没见过其它语言使用类似的方法处理范围问题.

>> 没有引用. PHP所谓的引用是个真正的别名; 这无疑是一种倒退, 不像 Perl 的引用, 也没有像 Python 那样的对象标识传递.

>> 没有明显的方式检测和取消引用.

>> 「参照」は、言語内で変数を一意にします。PHP は動的に型指定されるため、変数は通常は型付けされません。変数が参照されると、参照に加えて、関数の定義、変数の構文、代入が変更されます。どこでも起こり得る)、それは常に参照になります。

>> 一部の「SPL タイプ」は変数でも機能します。 new SplBool(true); $x = "foo"; これは静的型付けに似ています。

>> 内に存在しないキーを参照することもできます。変数 (配列になります) を使用すると、通常は通知が発行されますが、これは通知されません。

>> 関数によって定義された定数は、これより前に存在しませんでした。定数を使用して Perl の動作を効果的にコピーする可能性があります。)

>> 関数名とクラス名は大文字と小文字を区別しません。これにより、メソッドにキャメルケースの名前を使用することが奇妙になります。 ; > array() およびいくつかの同様の構造は関数ではありません。 $func = "array"; > 配列のアンパックは list($a,$b) を使用して行うことができます。 = . ...操作は完了しました。 list() は関数のような構文であり、実際に専用の構文がない理由もわかりません。また、名前がなぜそれほど混乱しているのかもわかりません。 .

>> ( int) は明らかに C のように設計されていますが、言語には int と呼ばれるものはありません。これを試してみてください。 var_dump(int) は機能しません。引数がキャスト演算子のように見えるため、解析エラーです >> (integer) は、(bool)/(boolean) および (float)/(double) のエイリアスです。 /(real).

>> ; 配列に変換するための (array) 演算子と、オブジェクトに変換するための (object) 演算子があります。しかし、多くの場合、使用例があります。 array) を使用して関数パラメータを作成します。これは、単一要素である場合も、リストである場合もあり、同じように扱われます。ただし、誰かが単一のオブジェクトを渡した場合、それを配列に変換すると、実際には を含む配列が生成されるため、これは信頼できません。 (オブジェクトへの変換は、逆の転送操作を実行します。)

>> include() のような関数は、基本的に C の #include であり、他のファイルのソース コードをファイルにダンプします。 PHP コードでも同様です。

>> ネストされた関数やローカル スコープの関数やクラスは存在せず、ファイルとその変数はすべてグローバルです (ファイルに機能を与えます)。変数にアクセスするには)、関数とクラスはグローバル スコープに保存されます

>> 配列を追加するには、$foo[] = $bar を使用します。

>> empty($var) は非常に極端で、変数以外の関数として動作しないもの、たとえば empty($var || $var2) は解析エラーになります。パーサーはなぜ空について知る必要があるのですか?

>> まだいくつかの冗長な構文ブロック: if (...): ... endif; など

エラー処理

> ;> PHP の固有の演算子は @ (実際には DOS から借用したもの) であり、PHP エラーはスタック トレースを提供しません (ただし、致命的なエラーではありません)。 -- 以下を参照してください。)

>> PHP の解析エラーは通常、解析されたステータスのみをスローするため、デバッグが困難になります。 < 演算子を「内部的に」と言っていますが、プログラマに表示される :: または << は、ほとんどのエラー処理でサーバーに出力されます。

>> E_STRICT はそのように見えますが、実際に何をするのかを示すドキュメントはありません

>> E_STRICT を除くすべてのエラー カテゴリ。

>> ここで E_STRICT がどのように適用されるかはわかりませんが、次のとおりです。

> $foo->x などの存在しないオブジェクト プロパティ。(警告)

>> 関数名、変数名、またはクラス名として変数を使用します。未定義の定数を使用しようとしました。(注意)

>> 非オブジェクト型のプロパティにアクセスしようとしました。存在しない変数名です。(注意)

> 2 $foo::x. (致命的なエラー)

>> 関数名、変数名、またはクラス名として文字列定数を使用しています。 )

>> 明示的に定義された関数を呼び出そうとしています (致命的なエラー)。

>> Leaving off a semicolon on the last statement in a block or file. (parse error)

>> 使用 list 和其它准内建宏作为方法名. (parse error)

>> 用下标访问函数的返回值, 如: foo()[0]. (parse error; 已在 5.4 中修复)

在列表的其他地方也有几个关于其它怪异解析错误的好例子

>> __toString 方法不能抛出异常. 如果你尝试, PHP 將 ... 呃, 抛出一个异常. (实际上是个 fatal error, 可以被通过的, 除了...)

>> PHP 错误和 PHP 异常是完全不同的物种. 它们不能相互作用.

>> PHP 错误 (内部, 称为 trigger_error)不能被 try/catch 捕获.

>> 同样, 异常不能通过 set_error_handler 安装的错误处理器触发错误.

>> 作为替代, 有一个单独的 set_exception_handler 可以处理未捕获的异常, 因为用 try 块包装你程序入口在 mod_pho 模块中是不可能的.

>> Fatal 错误 (例如, new ClassDoesntExist()) 不能被任何东西捕获. 大量的完全无害的操作会抛出 fatal 错误, 由 于一些有争议的原因被迫终结你的程序. 关闭函数仍然运行, 但它们无法获取栈轨迹(它们运行在上层), 它们很难告知该程序是由一个错误还是程序的正常运行结束.

>> 没有 finally 结构, 使得包装代码 (注册处理器, 运行代码, 注销处理器; monkeypatch, 运行测试, unmonkeypatch) 很难看, 很难写. 尽管 OO 和异常大量的复制了Java的模式, 这是故意的, 因为 finally "在PHP上下文中, 只得其形不得其神".Huh ?

函数

>> 函数调用似乎相当昂贵.

>> 一些内建函数与 reference-returning 函数交互, 呃, 一种奇怪的方式.

>> 正如在别处提到的, 很多看起来像函数或者看起来它们应该是函数的东西实际上是语言的构成部分, 因此无法像正常函数一样的工作.

>> 函数参数可以具有 "类型提示", 基本上只是静态类型. 你不能要求某个参数是 int 或是 string 或是 对象 或其它 "核心" 类型, 即使每个内建函数使用这种类型, 可能因为 int 在PHP中不是个东西吧. (查看上面关于 (int) 的讨论). 你也不能使用特殊的被大量内建函数使用的伪类型装饰: mixed, number, or callback.

>> 因此, 下面:

<ol class="dp-c">
<li class="alt"><span><span class="keyword">function</span><span> foo(string </span><span class="vars">$s</span><span>) {}  </span></span></li>
<li>
<span>foo(</span><span class="string">"hello world"</span><span>); </span>
</li>
</ol>

产生错误 the error:

PHP Catchable fatal error: Argument 1 passed to foo() must be an instance of string, string given, called in...

>> 你可能会注意到 "类型提示" 实际上并不存在; 在程序中没有 string 类. 如果你试图使用 ReflectionParameter::getClass() 动态测试类型提示, 將会得到类型不存在, 使得实际上不可能取得该类型名.

>> 函数的返回值不能被推断

>> 將当前函数的参数传给另一个函数 (分派, 不罕见) 通过 call_user_func_array('other_function', func_get_args())完成. 但 func_get_args 在运行时抛出一个 fatal 错误, 抱怨它不能作为函数参数. 为什么为什么这是个类型错误? ( 已在 PHP 5.3 中修复)

>> 闭包需要显示的命名每个变量为 closed-over. 为什么解析器不想办法解决? (Okay, it’s because using a variable ever, at all, creates it unless explicitly told otherwise.)

>> Closed-over 变量, 通过和其它函数参数相同的语义"传递". 这样的话, 数组和字符串等等, 將以传值方式传给闭包. 除非使用 &.

>> 因为闭包变量会自动传递参数, 没有嵌套范围, 闭包不能指向私有方法, 不管是否定义在类中. ( 可能在 5.4 中修复? 不清楚.)

>> 函数没有命名参数. 实际上被 devs 显示拒绝, 因为它 "会导致代码臭味".

>> Function arguments with defaults can appear before function arguments without, even though the documentation points out that this is both weird and useless. (So why allow it?)

>> 向函数传递额外的参数会被忽略 (除了内建函数, 会抛出异常). 丢失的参数被假定为 null.

>> "可变" 函数需要 func_num_args, func_get_arg, 和 func_get_args. 这类事情没有语法.

OO

>> PHP の関数部分は C のように設計されていますが、オブジェクト指向は Java のように設計されています。これがどれほど不協和音であるかはまだわかりません。大文字のグローバル関数。重要な組み込みクラスはキャメルケースで名前が付けられ、getFoo のような Java スタイルのプロパティ アクセサーを備えています。これは動的言語です。Perl、Python、Ruby にはすべて「プロパティ」にアクセスするという概念があります。 " コードを通して; PHP 面倒な __get などがあるだけです。型システムは低レベル Java 言語を中心に設計されています。Java と PHP は同じ時代にあります。Java は意図的に制限を増やして Java をコピーしました。理解できません。 it.

>> メタプログラミングは、関数と同様に、文字列名を介してクラスを指す必要があり、(Perl とは異なり) 組み込み型を作成することはできません。

>>instanceof は演算子ですが、ほとんどの言語には特別な関数と構文が組み込まれています。クラスはファーストクラスではありませんか?かどうかはわかりません。)

>> ただし、オブジェクトが実際に文字列で指定されたクラスになることを許可するかどうかを指定する is_a 関数があります。 get_class は関数です; typeof 演算子はありません

>> ただし、これは組み込み型では機能しません (この場合、int は問題になりません)。 is_int などが必要です。

>> 右辺値は変数またはリテラルでなければなりません。それ以外の場合は解析エラーが発生します。

>> >> OO の設計は Perl と Java を組み合わせたモンスターです

> オブジェクトのプロパティは $obj->foo を経由しますが、クラスのプロパティは $obj::foo です。他の言語でもこれを行うか、その使用方法を参照してください。ただし、インスタンス メソッドは静的 (Class::method) 経由で呼び出すことができます。他のメソッドから呼び出された場合は、通常のメソッドとみなされます。現在の $this を呼び出してみてください。

>> Java 開発者を説得しようとしているのは個人的な好みの問題であることはわかっていますが、私はそうではありません。これらのことが動的言語に必要な理由を知ってください。C++ では、そのほとんどがアセンブリ時およびコンパイル時の名前解決に関連しています。

>> サブクラスによってカバーされるパブリック メソッドもオーバーライドできません。スーパークラスのプライベート メソッドは表示されず、個別に呼び出すことができます。モック オブジェクトをテストする場合などに問題が発生します。 (関数ではなく) 特別な構文であり、この曖昧さの理由は不明ですが、クラスは正常に動作します ($foo->list() は構文エラーではありません)。 >> コンストラクター引数の解析時に例外がスローされた場合 (例: new Foo(bar()) および bar() throws)、コンストラクターは呼び出されませんが、デストラクターは呼び出されます (PHP 5.3 で修正)。

>> __autoload および解析関数の例外は致命的なエラーを引き起こす可能性があります。

>> __construct は、Python の __init__ のような初期化関数ではありません。

>> デフォルトの初期化関数はありません。親クラスが独自の __construct メソッドを定義していない場合、致命的なエラーが発生します。これは言語仕様の一部 (... as... など) ですが、実際にはこのインターフェイスの組み込み実装はありません (配列の場合など)。配列反復子が必要な場合はラップする必要があります。 ArrayIterator を使用すると、イテレーターを最上級のオブジェクトとして機能させる組み込みの方法はありません。

>> 文字列、数値、配列にはすべて String 変換メソッドがあり、関数とクラスはこれに大きく依存します。ただし、__toString が定義されていない場合は、組み込みまたはカスタム オブジェクト (またはクロージャ) を文字列に追加すると、エラーが発生する可能性があります。

>> インスタンス メソッドの静的変数はオーバーロードできません。それらの値は、クラスの複数のインスタンス間で共有されます。

標準ライブラリ

Perlは「一部にはアセンブリが必要です」。PHPは「キッチンのシンク、カナダ製ですが、すべての蛇口が付属しています」。は C" でブランド化されています。

一般化

>> 型システムはありません。PHP をコンパイルできますが、php.ini を介して何をロードするかを指定する必要があります。オプションは存在します (その内容を

> 名前空間は最近の機能であるため、グローバル名前空間の一部の機能はまったく中断されません。ライブラリは非常に一貫性がありません

>> ; アンダースコアとアンダーラインなし: strpos/str_rot13、php_uname/phpversion、base64_encode/urlencode、gettype/get_class

>> "to" を 2: ascii2ebcdic、bin2hex、deg2rad、strto lower、strtotime

>> オブジェクト + 動詞から動詞 + オブジェクト: Base64_decode、str_shuffle、var_dump と create_function、recode_string

>>パラメータシーケンス: array_filter($input, $callback) 対 array_map($callback, $input)、strpos($haystack, $needle) 対 array_search($needle, $haystack)

>> プレフィックスの混乱: usleep と microtime

>> 名前の i がどこにあるかによって異なります

>>以下が含まれます:

>> Bind ImageMagick、bind GraphicsMagick (ImageMagick の派生)、いくつかの関数は EXIF データを検出できます (そのうちの ImageMagick はすでに実行できます)

>> bbcode を解析する関数いくつかの小さなフォーラム パッケージで使用される非常に特殊なタグです。

>> DOM (OO)、DOM XML (not)、libxml、SimpleXML、「XML Parser」、およびもちろん、いくつかの違いはありますが、その違いはご自由に理解してください。SPPLUS と MCVE という 2 つの特別なクレジット カード プロセッサに依存しています。 ?

>> MySQL データベースにアクセスする 3 つの方法: mysql、mysqli、PDO 抽象化

C は、高レベルの動的型付け言語である必要があります。そして、標準ライブラリの多くの部分は、次のような C API の単なるラッパーです:

>> PHP はアドホック ハッシュやより簡単にパラメータを返すことができます

。 >> 少なくとも 12 個の関数が、特定のサブシステムで最新のエラーを取得するように設計されています (下記を参照)。PHP には 8 年前から例外処理機能がありますが、mysql_real_escape_string はすでに存在します。 MySQL C API の一部であるため、同じパラメータを持つ mysql_escape_string

>> 複数の MySQL 接続を使用するには、各関数の明示的なサポートが必要です。接続ハンドルを渡します

>> たとえば、dba_firstkey を呼び出さずに dba_nextkey を呼び出すと、大量の ctype_* 関数が存在します。

ジェネリック主義

ある関数が 2 つのわずかに異なることを行う場合、PHP は 2 つの関数を作成します。

Perl では、どのようにして逆ソートを行うことができますか? { $b <=> $a} を使用します。PHP では、 rsort() という特殊な関数があります。 C エラーと同様:curl_error、json_last_error、openssl_error_string、imap_errors、mysql_error、xml_get_error_code、bzerror、date_get_last_errors など?

>> 並べ替え関数: array_multisort、arsort、asort、ksort、krsort、natsort、natcasesort、sort、rsort、 uasort、uksort、usort

>> テキスト検索関数: ereg、eregi、mb_ereg、mb_eregi、preg_match、strstr、strchr、stristr、strrchr、strpos、stripos、strrpos、strripos、mb_strpos、mb_strrpos、およびそのバリエーションreplaces

>> には多数のエイリアスがあります: strstr/strchr、is_int/is_integer/is_long、is_float/is_double、pos/current、sizeof/count、chop /rtrim、implode/join、die/exit、trigger_error/ user_error…

>> scandir は、現在指定されているディレクトリ内のファイルのリストを返します(有益である可能性があります)。この関数は、ソートされたファイルのリストを返します。これらは明らかに並べ替えには不十分です。 str_split は文字列を同じ長さのチャンクに分割し、区切り文字で結合します。 ;> 圧縮ファイルの読み取りには、形式に応じて別の関数セットが必要で、bzip2、LZF、phar、rar、zip、gzip/zlib など、6 つの関数セットが異なります

> ;> 引数配列を使用して関数を呼び出すのは非常に面倒なので (call_user_func_array)、printf/vprintf や sprintf/vsprintf のようなものもありますが、同じことを行いますが、1 つは多くのパラメーターを受け取り、もう 1 つはパラメーター配列を受け取ります。 text

>> /e (eval) フラグを指定した preg_replace は、一致する部分を置換対象の文字列に置き換えてから、それを評価します。

>> strtok の設計は明らかに C と同等です。この関数は、多くの理由から悪い考えであると考えられてきましたが、PHP では簡単に配列を返すことができ (C では扱いにくい)、strtok(3) の使用法の多くのハック (どこかに文字列を変更) がここでは使用できません。

>> parse_str はクエリ文字列を解析しますが、関数名からはわかりません。代わりに register_globals を実行し、クエリ文字列をローカル スコープ変数にダンプします (もちろん、クエリ文字列を埋めるための配列は何も返されません)。 )

>> このアプローチを採用する他のすべての文字列分割実装では、文字列を文字に分割する必要があることを意味します。

>> 日付の書式設定には、ローカル ロケール処理用の C API に似た strftime がありますが、これは構文がまったく異なります。英語で使用されます。

>> "gzgetss -- gz ファイルの行ポインタを取得し、HTML タグを削除します。"

>> はすべて「マルチバイト」に関するもので、文字セットの問題を解決します

>> 一部の関数では、文字セットを指定できます。ただし、これは、すべてのパラメーターと戻り値に依存します。リフレクション

>> テキストと変数に焦点を当てた関数が多数あります

>> 一見すると、PHP ダイナミックを使用する方法はいくつかあります。明らかな違いや相対的な利点はありません。クラス ツールはカスタム クラスを変更できません。ランタイム ツールはカスタム クラスを変更できます。リフレクション* クラスは、関数のプロパティを報告することを目的としています。これらのサブシステムは独立していますか、関連していますか?

>> get_class($obj) は、呼び出されたクラスの関数名を返します。同じ関数はまったく異なることを行います: get_class(null)... は後者と同じように動作します。驚くべきことに、stream_* クラスではカスタムの実装が可能です。 fopen やその他の組み込みのもので使用するストリーム オブジェクト (ファイル処理など) は、

>> クロージャ オブジェクトを受け入れることができません。クロージャを文字列に変換できないことを示すエラーがスローされます

>> fork と exec は組み込みではありません。 pcntl 拡張子ですが、デフォルトでは含まれていません。popen は、任意の PHP セッション文字列を読み取るために使用されますが、結果を $ にダンプします。 _SESSION は、その値を返す代わりに、エラーが発生したときにcurl_errorを変更しません。

>>分、秒、月、日、年

データ操作

プログラムは、awk から Prolog、C に至るまで、データ操作を中心に設計されています。データを操作することはできず、何もできません。

Numbers

>> 整数は、同時代の PHP プラットフォームでは符号付き 32 ビット数値であるため、自動の bigint 改善はありません。数学演算は、CPU アーキテクチャに応じて異なる結果になる可能性があります。大きな整数に対する唯一の選択肢は、GMP または BC ラッパー関数を使用することです (開発者が新しい別の 64 ビット型を作成した可能性があります。これはおかしなことです)。

>> PHP は 0 から始まる 8 進数の構文をサポートしているため、012 は 10 になります。ただし、08 は 0. 8 (または 9) になり、それ以降の数字は構文エラーになります。

>> pi は関数です。または定数 M_PI があります。

>> 実際には、ASCII 関数のみがサポートされています。これは少しヒットです

>> これは、組み込みの文字列関数を使用して UTF-8 テキストを処理することにはリスクがあることを意味します。

>> 同様に、ASCII の外には、大文字と小文字を区別する関数の拡張バージョンはありますが、それらは é が É と等しいとはみなしません。例: "$foo['key']" のように、変数内でキーを補間することはできません。は構文エラーです。引用符を外したり、${...}/{ $...}

>> "${foo[0]}" を使用したりすることもできません。 「${foo[0][0]}」は構文エラーです。Perl のような構文 (根本的に異なる 2 つの言語) のコピーですか?

配列

、Sao Nian です。

>> 这家伙扮演list数据类型, 操作hash, 和排序set, 解析 list, 偶尔会有些奇怪的组合. 它是怎样执行的? 以何种方式使用内存? 谁知道? 不喜欢, 反正我还有其它的选择.

>> => 不是操作符. 它是个特别的结构, 仅仅存在于 array(...) 和 foreach 结构中.

>> 负值索引不工作, 尽管 -1 也是个和0一样的合法键值.

>> 尽管这是语言级的数据结构, 但没有简短语法; array(...)是简短语法. (PHP 5.4 带来了"literals", [...].)

>> => 结构是基于 Perl , Perl允许 foo => 1 而不用引号. 在PHP中, 你这么做会得到警告; 没有无需引号创建 hash 字符串键值的方式.

>> 数组处理函数常常让人迷惑或有不确定行为, 因为它们不得不对 lists, hashes, 或可能两者的结合体做运算. 考虑 array 分组, "计算arrays的不同部分".

<ol class="dp-c">
<li class="alt"><span><span class="vars">$first</span><span>  = </span><span class="keyword">array</span><span>(</span><span class="string">"foo"</span><span> => 123, </span><span class="string">"bar"</span><span> => 456);  </span></span></li>
<li>
<span class="vars">$second</span><span> = </span><span class="keyword">array</span><span>(</span><span class="string">"foo"</span><span> => 456, </span><span class="string">"bar"</span><span> => 123);  </span>
</li>
<li class="alt">
<span class="func">echo</span><span> var_dump(</span><span class="func">array_diff</span><span>(</span><span class="vars">$first</span><span>, </span><span class="vars">$second</span><span>));  </span>
</li>
</ol>

这段代码將做什么? 如果 array_diff 將参数以 hashes 看待, 它们明显是不同的; 相同的keys有不同的值. 如果以list看待, 它们仍然是不同的; 值的顺序不同.

事实上 array_diff 认为它们相等, 因为它以 sets 对待: 仅仅比较值, 忽略顺序.

>> 同样, array_rand 随机选择keys时, 也有奇怪的行为, 这对大多数需要从列表中挑出东西的用例没什么帮助.

尽管大量PHP代码依赖key的顺序:

<ol class="dp-c">
<li class="alt"><span><span class="keyword">array</span><span>(</span><span class="string">"foo"</span><span>, </span><span class="string">"bar"</span><span>) != </span><span class="keyword">array</span><span>(</span><span class="string">"bar"</span><span>, </span><span class="string">"foo"</span><span>)  </span></span></li>
<li><span> </span></li>
<li class="alt">
<span class="keyword">array</span><span>(</span><span class="string">"foo"</span><span> => 1, </span><span class="string">"bar"</span><span> => 2) == </span><span class="keyword">array</span><span>(</span><span class="string">"bar"</span><span> => 2, </span><span class="string">"foo"</span><span> => 1) </span>
</li>
</ol>

>> 如果两个数组混合的话, 会发生什么? 我留给读者自己弄清楚. (我不知道)

>> array_fill 不能创建0长度的数组; 相反它会发出警告并返回 false.

>> 所有的(很多的...) 排序函数就地操作而什么都不返回. 想新建一个已排序数组的拷贝, 没门; 你不得不自己拷贝数组, 然后排序, 然后再使用数组.

>> 但 array_reverse 返回一个新数组.

>> 一堆被排序的东西和一些键值对听起来像是个某种强大的处理函数参数的方式, 但, 没门.

非数组

>> 标准库包含 "快速哈希", "特定的强类型"的hash结构OO实现. 然, 深入它, 有4类, 每种处理不同的键值对类型组合. 不清楚为什么内建的数组实现不能优化这些极其普通情况, 也不清楚它相对的性能怎样.

>> 有个 ArrayObject 类 (实现了4个不同的接口) , 它包装数组让它看起来像对象. 自定义类可以实现同样的接口. 但只有限的几个方法, 其中有一半不像内建的数组函数, 而内建的数组函数不知道怎样对ArrayObject或其它的类数组的类型操作.

函数

>> 函数不是数据. 闭包实际上是对象, 但普通的函数不是. 你甚至不能通过它们裸名称引用它们; var_dump(strstr) 会发出警告并猜测你的意思是字符串字面量, "strstr". 想辨别出字符串还是"函数"引用, 没门.

>> create_function 基本上是个 eval 的包装者. 它用普通的名字创建函数并在全局范围安装它(因此永远不会被垃圾回收---不要在循环中使用!). 它实际上对当前上下文一无所知, 因为它不是闭包. 名字包含一个 NUL 字节, 因此永远不会与普通函数冲突 (因为如果在文件的任何地方有 NUL的话, PHP 的解析器会失败).

>> Declaring a function named __lambda_func will break create_function—the actual implementation is to eval-create the function named __lambda_func, then internally rename it to the broken name. If __lambda_func already exists, the first part will throw a fatal error.

其它

>> 对 NULL 使用 (++) 生成 1. 对 NULL 用 (--) 生成 NULL.

>> 没有生成器.

Web 框架

执行环境

>> 一个单一共享文件 php.ini, 控制了 PHP 的大部分功能并织入了复杂的针对覆盖什么与何时覆盖的规则. PHP软件能部署在任意的机器上, 因此必须覆盖一些设置使环境正常, 这在很大程序上会违背像 php.ini 这样的机制的使用.

>> PHP基本上以CGI运行. 每次页面被点击, PHP 在执行前, 重编译整个环境. 就连 Python 的玩具框架的开发环境都不会这样.

>> 这就导致了整个 "PHP 加速器" 市场的形成, 仅仅编译一次, 就能加速PHP, 就像其它的语言一样. Zend, PHP的幕后公司, 將这个做为它们的商业模式.

>> 長い間、PHP エラーはデフォルトでクライアントに出力されていましたが、これは真実ではないと思いますが、それでも時折 mysql エラーがページに表示されます。 . Top.

>> タグの外側の空白は、PHP によってテキストとして扱われ、応答に組み込まれます (または、「ヘッダーは既に送信されました」エラーが発生します)。 ). このアプローチは、?>Close タグを無視することです。

デプロイメント

デプロイメント方法は、PHP の最も高度な部分としてよく引用されます。はい、これは Python よりも優れています。プロセス全体を開始する必要がある Rury や Perl の方が簡単ですが、PHP にはまだ不十分な点がたくさんあります。

これには最小限のコストと多くの利点があります。 : サーバーとアプリケーションを個別に管理でき、マシンの数に応じて複数または少数のアプリケーション プロセスを実行できます。複数の Web サーバーを必要とせず、異なるユーザーでアプリケーションを実行でき、Web サーバーを選択できます。 、Web サーバーに警告せずにアプリケーションを削除でき、アプリケーションなどを Web サーバーに直接接続するのはばかげており、PHP ごとにそうする正当な理由はありません。アプリケーションは php.ini を使用しますが、php.ini ファイルは 1 つだけであり、共有サーバー上でそれを変更する必要がある場合、または異なる設定が必要な 2 つのアプリケーションを実行している場合は問題ありません。運が良ければ、組織に問い合わせる必要があります。必要な設定をすべて適用して、ini_set や Apache 設定ファイル、または .htaccess 設定などに適用できる場合は、おそらくそれができます。設定値を取得する方法を確認するには、多くの場所を確認する必要があります。

>> 同様に、PHP アプリケーションを「分離」する方法は、システムの他の部分に依存するため、2 つ実行する必要があります。アプリケーションに別のライブラリ バージョンが必要ですか? 別の人の Apache のコピーを構築し始めます

>> 「ファイルのバンドル」アプローチは、ルーティングを病的に愚かなものに見せるだけでなく、次のことも行う必要があります。 URL レベルはコード ツリーのレベルでもあり、ファイルの直接読み込みを避けるために C などで保護する必要があるため、アクセスできるものを制御するためにホワイトリストまたはブラックリストに注意してください。 mod_php では、ファイル システム内のすべてが潜在的なエントリであり、エントリは 1 つだけであり、呼び出しの有無は URL によってのみ制御されます。

>> アップグレードの合間にユーザーがサイトをクリックしたときにアプリケーションがクラッシュして未定義の動作を示すようにしない限り、CGI スタイルで実行される多数のファイルをシームレスにアップグレードすることはできません。 PHP を実行するように Apache を設定するのは「簡単」ですが、それでも落とし穴がいくつかあります。PHP ドキュメントでは、SetHandler を使用して .php ファイルを PHP モードで実行することを推奨しています。AddHandler は正常に実行されているように見えますが、実際には次のような問題が発生します。

AddHandler を使用すると、Apache に「php を実行する」ように指示することになります。これは .php ファイルを処理する方法の 1 つですが、Apache はファイル拡張子をそのように考慮するようには設計されていません。 Apache の場合、ファイルは同時に任意の数の拡張子を使用して、公開ディレクトリにファイルを保存できるようにする必要があります。 PHP ファイルをアップロードする場合は、ファイルに .php 拡張子が付いていないことを確認するだけです。すべての攻撃 foo.php.txt という名前のファイルをアップロードするだけで、アップロード ツールは問題を認識せず、Apache はそれが PHP であると認識します。問題は、PHP を「簡単にする」古いコードを実行するように設定する必要があるということです。これは理論的な問題ではありません。似たような

足りない機能

を持つ実際のサイトをたくさん見つけました。これらはすべて、Web アプリケーションの構築を中心にしていると思います。PHP は非常に合理的で、売りの 1 つです。重要なのは、それが「Web 言語」であることです。PHP は単なるテンプレートです。XSS フィルターは存在しません。 >> CSRF 保護は自分で行う必要があります

> PDO のようなものは、それぞれの特定のデータベースの API を個別に抽象化する必要があります。 ; ルーティング システムはありません。

>> 開発サーバーはありません。 > 一貫した展開メカニズムはなく、「すべてのファイルをサーバーにコピーする」だけです。

言語境界

PHP のセキュリティは、ある言語からデータを取り出して別の言語にダンプするため、さらに悪化する可能性があります。これは SQL では何の意味も持たないかもしれませんが、これは HTML ではまったく当てはまります。さらに悪いことに、誰かが「入力をサニタイズする必要がある」と叫ぶのは完全に間違いです。データのブロックを完全に「サニタイズ」するような魔法はあり得ません。必要なのは、何かを言うことだけです。言語に関して: SQL はプレースホルダーを使用し、プロセス インキュベーションはパラメーター リストを使用します。

>> PHP は「サニタイズ」を推奨しています。これを行うことができるデータ フィルタリング拡張機能があります

>> 、その他のスラッシュ関連のものはゴミで役に立たない

>> プロセスを安全に実行する方法はありません。エスケープがおかしいので、デフォルトのシェルが正しいエスケープを使用するか、pcntl_fork_exec と pcntl_exec を手動で使用してください。

>> すべてのエスケープ コマンドとエスケープ パラメータはほぼ同じ説明で存在します。 注 Windows では、エスケープ パラメータは機能しません。 (Bourne シェル構文を前提としているため)、escape コマンドは、大量の句読点をスペースに置き換えるだけです。これは、Windows コマンドのエスケープ動作を誰も理解できないためです (何をしようとしても、黙って中断される可能性があります)。 > 現在でも広く使用されているオリジナルの組み込み MySQL バインディングでは、プリペアド ステートメントを作成できません。

SQL インジェクションに関する PHP ドキュメントのアドバイスは、sprintf や is_numeric を使用した型チェックなどの実践を手動で行うのは依然として面倒です。どこでも mysql_real_escape_string を使用するか、どこでも addslashes を手動で使用します (これは「より便利かもしれません!」)。ユーザーレベルを除いて、PDO やパラメーター化については言及されていません。私が少なくとも 2 つの PHP 開発者に苦情を申し立てたコメントにヒントがあります。何年も前に彼は心配していましたが、ページはデフォルトで無効になっており、5.4 では削除されました

>>。 ; include は HTTP URL を受け入れます。

>> デフォルトではセキュアに近いですが、概念をまったく理解していません。

PHP インタープリター自体はいくつかの厄介なセキュリティ問題

>> 2007 年、パーサーには整数オーバーフローの脆弱性があり、if(size > INT_MAX) が NULL を返すようになりました (そうでない人にとっては)。 C を使用する必要があります。かつては INT_MAX が変数に適した最大の整数でした。残りはここから理解できると思います。)

>> 最近、PHP 5.3.7 には crypt() 関数が含まれています。

>> PHP5.4 には、Content-Length ヘッダー (誰でも設定可能) が必要であり、より多くのメモリを割り当てようとするため、誰でも任意のパスワードでログインできる脆弱性があります。 。これは悪い考えです。

もっと掘り下げることもできますが、重要なのは、たくさんあるということではありません。ここでは、それらが独自に到着します

いくつかのコメントは、私が結論を出していないと当然に指摘するでしょう。ここまで読んだ方は、私に同意していただいたと思います:)

PHP だけを知っていて、他のことを学ぶことに興味がある場合は、Python チュートリアルをチェックしてください。 Web 用に用意された Flask を試してみてください (私はそのテンプレート言語の大ファンではありませんが、これは非常に優れています。OK で十分です)。これにより、アプリが複数の部分に分割されますが、見た目は一貫していると思われます。これについては後で記事を書きます。ここで述べた Web スタックとは異なり、言語全体のめまぐるしい紹介です

後で、または大規模なプロジェクトの場合は、次のようなサイトを構築するための複雑なフレームワークである Pyramid が必要になる場合があります。ジャンゴ サイト

英語:

http://www.bkjia.com/PHPjc/445698.html

www.bkjia.com

本当

http://www.bkjia.com/PHPjc/445698.html
技術記事

翻訳者注: この記事は非常に長く、読みにくいかもしれません。私は地球上のほとんどのテクノロジーについて不満を持っています。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。