PHPは簡単だと言われていますが、使いこなすのは簡単ではありません。それを使用できることに加えて、その根本的な動作原理を知る必要もあります。
PHP は Web 開発に適した動的言語です。具体的には、C言語を使用して多数のコンポーネントを実装するソフトウェアフレームワークです。より狭い意味で見ると、強力な UI フレームワークと考えることができます。
PHP の基礎となる実装を理解する目的は何ですか?動的言語をうまく使用するには、まずメモリ管理とフレームワーク モデルを理解する必要があります。拡張された開発を通じて、より強力な機能を実現し、プログラムのパフォーマンスを最適化できます。
PHP の設計コンセプトと特徴
マルチプロセス モデル: PHP はマルチプロセス モデルであるため、異なるリクエストが相互に干渉することはなく、リクエストのハングアップがサービス全体に影響を与えることはありません。時代とともに、開発、PHP はすでにマルチスレッド モデルをサポートしています。
型の弱い言語: C/C++、Java、C#、その他の言語とは異なり、PHP は型の弱い言語です。変数の型は最初は決定されず、暗黙的または明示的な型変換が行われるため、Web 開発では非常に便利で効率的です。詳細については、「変数」で説明します。に詳しく記載されています。
エンジン (Zend) + コンポーネント (ext) モードは、内部結合を軽減します。
中間層 (sapi) は Web サーバーと PHP を分離します。
構文はシンプルで柔軟であり、あまり多くの仕様はありません。欠点があるとスタイルが混在しますが、プログラマがどんなに下手でも、突飛すぎて全体の状況を危険にさらすようなプログラムは書きません。
PHP の 4 層システム
PHP のコア アーキテクチャは以下のとおりです:
写真からわかるように、PHP は下から上に 4 層システムです:
Zend エンジン: Zend は純粋な C 実装を使用しており、PHP コード (字句解析や構文解析などの一連のコンパイル プロセス) を実行可能なオペコード処理に変換し、対応する処理メソッドを実装し、基本的なデータ構造 (ハッシュテーブルなど) を実装します。 oo)、メモリの割り当てと管理、および外部呼び出しに対応する API メソッドの提供。これはすべての周辺機能が Zend を中心に実装されています。
拡張機能: Zend エンジンを中心に、拡張機能はコンポーネントベースの方法でさまざまな基本サービスを提供します。一般的なさまざまな組み込み関数 (配列シリーズなど)、標準ライブラリなどはすべて拡張機能を通じて実装されており、ユーザーは次のことも行うことができます。必要に応じて独自の拡張機能を使用して、機能拡張やパフォーマンスの最適化などを実現します (たとえば、現在 Tieba で使用されている PHP 中間層やリッチ テキスト解析が拡張機能の代表的なアプリケーションです)。
Sapi: Sapi の正式名はサーバー アプリケーション プログラミング インターフェイスであり、Sapi は一連のフック関数を使用して、PHP が周辺データと対話できるようにします。これは、非常にエレガントで成功した PHP の設計です。それはsapiによって実現されました。 PHP自体を上位層のアプリケーションから切り離して分離することで、PHPは異なるアプリケーションとの互換性を考慮する必要がなくなり、アプリケーション自体も、それぞれの特性に応じて異なる処理方法を実装できるようになります。
上位層アプリケーション: これは、私たちが通常作成する PHP プログラムであり、Web サーバーを介して Web アプリケーションを実装したり、コマンドラインでスクリプト モードで実行したりするなど、さまざまな Sapi メソッドを通じてさまざまなアプリケーション モードを取得します。
PHP が車なら、車のフレームは PHP そのもの、Zend は車のエンジン、Ext の下にあるさまざまなコンポーネントは車の車輪、Sapi は道路とみなすことができます、
車さまざまな種類の道路を走行でき、PHP プログラムを実行するということは、車が道路を走行していることを意味します。したがって、高性能エンジン + 適切なホイール + 適切なトラックが必要です。
3.Sapi
前に述べたように、Sapi を使用すると、外部アプリケーションは一連のインターフェイスを通じて PHP とデータを交換し、さまざまなアプリケーションの特性に応じて特定の処理メソッドを実装できます。
apache2handler: これは。 WebサーバーとしてApacheを使用し、mod_PHPモードで実行する場合の処理方法でもあり、現在最も広く使用されています。
cgi: これは、有名な fastcgi プロトコルである Web サーバーと PHP の間の別の直接対話方法であり、近年、fastcgi+PHP がますます使用されており、非同期 Web サーバーでサポートされている唯一の方法でもあります。
cli: コマンドライン呼び出し用のアプリケーションモード
4. PHP 実行プロセスとオペコード
まず、PHP コードを実行するプロセスを見てみましょう。
図からわかるように、PHP は典型的な動的言語実行プロセスを実装しています。コードの一部を取得した後、字句解析、構文解析、その他の段階を経て、ソース プログラムは次のように翻訳されます。命令
(オペコード) を入力すると、ZEND 仮想マシンはこれらの命令を順番に実行して操作を完了します。 PHP 自体は C で実装されているため、最終的に呼び出される関数はすべて C の関数です。実際、PHP は C で開発されたソフトウェアと考えることができます。
PHP 実行の中核は、オペコードである翻訳された命令です。
オペコードは、PHP プログラム実行の最も基本的な単位です。オペコードは 2 つのパラメータ (op1、op2)、戻り値、および処理関数で構成されます。 PHP プログラムは最終的に、一連のオペコード処理関数の順次実行に変換されます。
いくつかの共通処理関数:
ZEND_ASSIGN_SPEC_CV_CV_HANDLER : 变量分配 ($a=$b) ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER:函数调用 ZEND_CONCAT_SPEC_CV_CV_HANDLER:字符串拼接 $a.$b ZEND_ADD_SPEC_CV_CONST_HANDLER: 加法运算 $a+2 ZEND_IS_EQUAL_SPEC_CV_CONST:判断相等 $a==1 ZEND_IS_IDENTICAL_SPEC_CV_CONST:判断相等 $a===1
5.HashTable — コアデータ構造
HashTable は、PHP のほぼすべての共通関数を実装するために使用されます。さらに、zend 内の関数シンボル テーブルやグローバル変数などの一般的なアプリケーションもハッシュ テーブルに基づいて実装されます。
PHP のハッシュ テーブルには次の機能があります:
典型的な key->value クエリをサポート
配列として使用可能
ノードの追加と削除は O(1) の複雑さ
key は混合型をサポート : アソシエーションは次の場所に存在します同時に配列の組み合わせインデックス array
Value は混合型をサポートします: array ("string", 2332)
は線形トラバーサルをサポートします: foreach など
Zend ハッシュ テーブルは典型的なハッシュ テーブルのハッシュ構造を実装し、同時に提供します追加することで二重にリンクされたリスト。配列を順方向と逆方向に走査する機能があります。その構造は以下のとおりです:
ご覧のとおり、ハッシュ テーブルにはキー -> 値の形式のハッシュ構造と二重リンク リスト モードの両方があり、高速検索と線形検索をサポートするのに非常に便利です。横断。
ハッシュ構造: Zend のハッシュ構造は典型的なハッシュ テーブル モデルであり、リンク リストを通じて競合を解決します。 Zend のハッシュ テーブルは自己成長するデータ構造であり、ハッシュ テーブルの数がいっぱいになると、動的に 2 倍に拡張され、要素の位置が変更されることに注意してください。初期サイズは8です。さらに、キー->値の高速検索を実行する場合、zend 自体も空間を時間に交換することでプロセスを高速化するいくつかの最適化を行っています。たとえば、変数 nKeyLength は各要素で使用され、キーの長さを識別して迅速に決定します。
二重リンク リスト: Zend ハッシュ テーブルは、リンク リスト構造を介した要素の線形走査を実装します。理論的には、走査には一方向リンク リストを使用するだけで十分です。二重リンク リストを使用する主な目的は、迅速に削除して走査を回避することです。 Zend ハッシュ テーブルは複合構造であり、配列として使用すると、一般的な連想配列をサポートし、連続したインデックス番号として使用したり、2 つを混合したりすることもできます。
PHP 連想配列: 連想配列は典型的な hash_table アプリケーションです。クエリ プロセスは次の手順を実行します (コードからわかるように、これは一般的なハッシュ クエリ プロセスであり、検索を高速化するためにいくつかの高速判断が追加されています):
getKeyHashValue h; index = n & nTableMask; Bucket *p = arBucket[index]; while (p) { if ((p->h == h) && (p->nKeyLength == nKeyLength)) { RETURN p->data; } p=p->next; } RETURN FALTURE;
PHP インデックス配列: インデックス配列は共通のものです。添字アクセスによる配列。たとえば、$arr[0]、Zend HashTable は内部で正規化され、インデックス タイプのキーにもハッシュ値と nKeyLength (0) が割り当てられます。内部メンバー変数 nNextFreeElement は現在割り当てられている最大 ID であり、プッシュするたびに自動的に 1 ずつ増加します。この正規化プロセスにより、PHP は連想データと非連想データの混合を実現できます。プッシュ操作の特殊性により、PHP 配列内のインデックス キーの順序は添え字のサイズではなく、プッシュの順序によって決まります。たとえば、$arr[1] = 2; $arr[2] = 3; 場合、Zend HashTable はそれらをインデックス キーとして扱います
PHP は弱い型付けの言語です。変数自体の型は厳密には区別されません。 PHP では、変数を宣言するときに型を指定する必要はありません。 PHP は、プログラムの実行中に変数の型の暗黙的な変換を実行する場合があります。 他の厳密に型指定された言語と同様に、プログラム内で明示的な型変換を実行することもできます。 PHP 変数は、単純型 (int、string、bool)、コレクション型 (配列リソース オブジェクト)、および定数 (const) に分類できます。上記の変数はすべて、内部では同じ構造 zval を持ちます。
Zval は、zend のもう 1 つの非常に重要なデータ構造で、PHP 変数の識別と実装に使用されます。そのデータ構造は次のとおりです:Zval は主に 3 つの部分で構成されます:
type: Type で記述される変数を指定します。 (整数、文字列、配列など)IS_LONG -> lvalue IS_DOUBLE -> dvalue IS_ARRAY -> ht IS_STRING -> str IS_RESOURCE -> lvalue
代入操作を実行するとき、zend は変数を同じ zval と ref_count++ に指し、設定解除操作中は対応する ref_count-1 を指します。破棄操作は、ref_count が 0 に減少した場合にのみ実行されます。参照割り当ての場合、zend は is_ref を 1 に変更します。
PHP 変数は参照カウントを通じて変数共有データを実現しますが、変数の 1 つの値を変更した場合はどうなるでしょうか?変数を書き込もうとするときに、その変数が指す zval が複数の変数で共有されていることがわかると、Zend は ref_count が 1 の zval をコピーし、元の zval の refcount をデクリメントします。このプロセスは「zval 分離」と呼ばれます。 」。コピー操作は書き込み操作が発生した場合にのみ実行されるため、参照変数の場合は、非参照型の要件と逆の要件がバンドルされる必要があります。 1 つの変数がすべてのバンドル変数を変更します。
整数と浮動小数点数は、PHP の基本的な型の 1 つであり、単純な変数でもあります。整数と浮動小数点数の場合、対応する値は zvalue に直接格納されます。タイプはそれぞれlongとdoubleです。
整数型の場合、C などの厳密に型指定された言語とは異なり、PHP は int、unsignedint、long、long
long およびその他の型を区別しないことがわかります。 1 種類の整数、つまりlong。このことから、PHP では、整数の値の範囲はコンパイラのビット数によって決まり、固定されていないことがわかります。
浮動小数点数の場合、整数と同様に、float と double は区別されず、double のみが区別されます。
PHP では、整数の範囲が範囲外になった場合はどうすればよいですか?この場合、自動的に double 型に変換されてしまいますので、これが原因で起こるトリックが多いので注意が必要です。
整数と同様、文字変数も PHP の基本型であり単純な変数です。 zvalue 構造から、PHP の文字列は、C++ の文字列と同様に、実際のデータへのポインターと長さ構造で構成されていることがわかります。 c とは異なり、長さは実際の変数で表されるため、その文字列はバイナリ データ (含む) にすることができます。
リソースの破壊: リソースのデータ型は多様です。 Zend 自体にはそれを破壊する方法はありません。したがって、ユーザーはリソースを登録する際に破棄機能を提供する必要があります。リソースの設定が解除されると、zend は対応する関数を呼び出して破棄を完了します。グローバルリソーステーブルからも削除してください。
リソースは、それを参照しているすべての変数がスコープ外になった後だけでなく、リクエストが終了して新しいリクエストが生成された後でも、長期間存続することができます。これらのリソースは、特に破棄されない限り、SAPI のライフサイクル全体にわたって存続するため、永続リソースと呼ばれます。多くの場合、永続リソースによりパフォーマンスがある程度向上します。たとえば、一般的な mysql_pconnect では、永続リソースは pemalloc を通じてメモリを割り当て、リクエストが終了しても解放されないようにします。 zend の場合、この 2 つ自体には区別がありません。
PHP ではローカル変数とグローバル変数はどのように実装されますか?リクエストの場合、PHP はいつでも 2 つのシンボル テーブル (symbol_table と
active_symbol_table) を参照でき、そのうち前者はグローバル変数を維持するために使用されます。後者は、現在アクティブな変数シンボル テーブルを指すポインターです。プログラムが関数に入ると、zend
はシンボル テーブル x をそれに割り当て、active_symbol_table を a に指します。このようにして、グローバル変数とローカル変数の区別が行われます。
変数値の取得: PHP のシンボル テーブルは hash_table を通じて実装され、取得時に、対応する zval が識別子に従ってテーブルから検索され、返されます。
関数でグローバル変数を使用する: 関数では、明示的に global を宣言することでグローバル変数を使用できます。 active_symbol_tableのsymbol_tableに同じ名前の変数への参照を作成します。symbol_tableに同じ名前の変数が存在しない場合は、それが最初に作成されます。
関連記事:
PHPの動作仕組みを徹底解釈。次の PHP 動作メカニズムのプロセスを見てみましょう: 1. PHP 関連のプロセスを手動で開始したことはありません。Ap...
以上がPHP の基本的な動作メカニズムと原理の説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。