ホームページ  >  記事  >  バックエンド開発  >  PHP の基本的な動作原理の詳細な紹介

PHP の基本的な動作原理の詳細な紹介

王林
王林オリジナル
2019-09-02 13:13:174579ブラウズ

PHP の基本的な動作原理の詳細な紹介

PHP は、Web 開発に適した動的言語です。具体的には、C言語を使用して多数のコンポーネントモジュールを実装するソフトウェアフレームワークです。強力な UI フレームワークです。

つまり、PHP 動的言語実行プロセス: コードを取得した後、字句解析、構文解析、その他の段階を経て、ソース プログラムが命令 (オペコード) に変換され、その後 ZEND 仮想マシンが実行されます。これらの命令を 1 回実行して操作を完了します。 PHP自体はCで実装されているため、最終的に呼び出される関数もCの関数となり、PHPはCで開発されたソフトウェアとみなすことができます。

1. PHP の設計思想と特徴

1. マルチプロセスモデル: PHP はマルチプロセスモデルであるため、異なるリクエストは発生しません。相互に干渉するため、リクエストの失敗がサービス全体に影響を与えないことが保証されており、現在、PHP はすでにマルチスレッド モデルをサポートしています。

2. 型付けが弱い言語: C/C、JAVA、C#、その他の言語とは異なり、PHP は型付けが弱い言語です。変数の型は最初に決定されるのではなく、動作中に決定され、暗黙的または明示的な型変換が発生する可能性があります。この仕組みの柔軟性は、Web 開発において非常に便利で効率的です。詳細は PHP で説明します。変数に詳しく記載されています。

3. エンジン (Zend) コンポーネント (ext) モードは、内部結合を軽減します。

4. 中間層 (sapi). Sapi の正式名は Server Application Programming Interface で、Web サーバーと PHP を分離します。

5. 構文はシンプルかつ柔軟で、あまり多くの仕様はありません。欠点はスタイルの混在につながります。

2. PHP の 4 層システム

PHP のコア アーキテクチャは次のとおりです:

PHP の基本的な動作原理の詳細な紹介

PHP は 4 層のシステムです。下から上へのレイヤー システム システム:

1. Zend エンジン: Zend は完全に純粋な C で実装されており、PHP のコア部分であり、PHP コード (字句解析、構文解析、その他のコンパイル プロセス) を実行可能ファイルに変換します。オペコードの処理と実装 対応する処理メソッド、基本的なデータ構造 (ハッシュテーブル、OO など) の実装、メモリ割り当てメカニズムと管理、外部呼び出しに対する対応する API メソッドの提供がすべての中核であり、すべての周辺機能は Zend を中心に実装されます。

2. 拡張機能: Zend エンジンを中心に、さまざまな基本サービスをコンポーネントベースで提供する拡張機能で、共通の各種組み込み関数 (配列系列) や標準ライブラリなどはすべて拡張機能によって実装されます。ユーザー 必要に応じて、独自の拡張機能の一般的なアプリケーションを実装することもできます)。

3. Sapi: Sapi の正式名は、サーバー アプリケーション プログラミング インターフェイスです。これは、サーバー アプリケーション プログラミング インターフェイスです。Sapi により、PHP は一連のフック関数を通じて周辺データと対話できます。これは非常にエレガントで、 PHP の設計が成功 Sapi により、PHP 自体が上位層のアプリケーションから分離・分離されることに成功 PHP は異なるアプリケーションとの互換性を考慮する必要がなくなり、アプリケーション自体も特性に応じて異なる処理方法を実装できるようになりました。

4. 上位層アプリケーション: これは私たちが通常作成する PHP プログラムです. さまざまな SPI メソッドを通じてさまざまなアプリケーション モードを取得できます. Web サーバーを介して Web アプリケーションを実装する方法、コマンド ラインのスクリプト モードで実行する方法、など待ってください。

私たちが必要とするもの: 高性能エンジン (Zend) 適切なホイール (Ext) 適切なトラック (Sapi)。

3. Sapi

Sapi を使用すると、外部アプリケーションが一連のインターフェイスを通じて PHP とデータを交換し、さまざまなアプリケーションの特性に応じて特定の処理メソッドを実装できるようになります。

1. apache2handler: Apache を Web サーバーとして使用し、mod_PHP モードで実行する場合の処理​​方法であり、現在最も広く使用されています。

2. cgi: これは、Web サーバーと PHP の間の別の直接対話方式であり、有名な fastcgi プロトコルです。最近、fastcgi PHP がますます使用されており、非同期 Web サーバーでサポートされている唯一の方式でもあります。 . ; 典型的なアプリケーション nginx サーバー; fastcgi は単なる PHP の拡張機能です。

FastCGI プロセス マネージャー (IIS ISAPI または Apache モジュール) は、Web サーバーの起動時にロードされます。

FastCGI プロセス マネージャーは、それ自体を初期化し、複数の CGI インタープリター プロセス (複数の php-cgi が表示されます) を開始します。そしてWebサーバーからの接続を待ちます。

クライアント要求が Web サーバーに到達すると、FastCGI プロセス マネージャーが CGI インタープリターを選択して接続します。 Web サーバーは、CGI 環境変数と標準入力を FastCGI サブプロセス php-cgi に送信します。

FastCGI サブプロセスは処理を完了すると、同じ接続から標準出力とエラー情報を Web サーバーに返します。 FastCGI 子プロセスが接続を閉じると、リクエストが処理されます。次に、FastCGI 子プロセスは、(Web サーバーで実行されている) FastCGI プロセス マネージャーからの次の接続を待機して処理します。 CGI モードでは、php-cgi はこの時点で終了します。

上記の状況では、CGI が通常どれほど遅いか想像できるでしょう。 PHP へのすべての Web リクエストは、php.ini を再解析し、すべての拡張機能を再ロードし、すべてのデータ構造を再初期化する必要があります。 FastCGI では、これらすべてがプロセスの開始時に 1 回だけ行われます。さらに、永続的なデータベース接続が機能するという利点もあります。

PHP の基本的な動作原理の詳細な紹介

PHP の基本的な動作原理の詳細な紹介

3. cli: コマンドラインで呼び出されるアプリケーションモード

コマンドラインインターフェース(英語:command-lineinterface、略称) : CLI) は、グラフィカル ユーザー インターフェイスが普及する前に最も広く使用されていたユーザー インターフェイスです。通常、マウスはサポートされていません。ユーザーはキーボードから指示を入力し、コンピューターはその指示を受信して​​実行します。これをキャラクター ユーザー インターフェイス (CUI) と呼ぶ人もいます。
コマンド ライン インターフェイス (CLI) は、ユーザーにとってグラフィカル ユーザー インターフェイス (GUI) ほど操作しにくいと一般に考えられています。コマンド ライン インターフェイス ソフトウェアは通常、ユーザーが操作コマンドを記憶する必要があるため、その特性により、コマンド ライン インターフェイスはグラフィカル ユーザー インターフェイスに比べてコンピューター システムのリソースを節約します。コマンドを覚えるという前提の下では、多くの場合、グラフィカル ユーザー インターフェイスを使用するよりもコマンド ライン インターフェイスを使用した方が高速です。したがって、グラフィカル ユーザー インターフェイスを備えたオペレーティング システムでは、オプションのコマンド ライン インターフェイスが保持されます。

4. PHP 実行プロセス

PHP の基本的な動作原理の詳細な紹介

PHP 動的言語実行プロセス: コードの一部を取得した後、字句解析後、文法解析などの段階を経て、ソース プログラムは命令 (オペコード) に変換され、ZEND 仮想マシンがこれらの命令を順番に実行して操作を完了します。 PHP自体はCで実装されているため、最終的に呼び出される関数もCの関数となり、PHPはCで開発されたソフトウェアとみなすことができます。

PHP 実行の中核は、オペコードでもある翻訳された命令です。

オペコードは、PHP プログラム実行の最も基本的な単位です。

コンピューターサイエンスの分野では、機械語の命令を記述するためにオペレーションコード(Operation Code、OPCode)が使用され、機械語の中で特定の演算を実行する部分を指定します。デバイスの命令仕様で指定された処理を行います。

オペコードは、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 は Zend のコア データ構造です。 PHP は、ほとんどすべての一般的な関数を実装するために使用されます. 私たちが知っている PHP 配列はその典型的なアプリケーションです. さらに、zend 内の関数シンボル テーブル、グローバル変数などもハッシュ テーブルに基づいており、次のような特徴があります:

1. 一般的なキー->値クエリをサポート

#2. 配列として使用可能

#3. ノードの追加と削除は O(1) の複雑さ

4. キーは混合型をサポートします: 同時に関連付けられた数値の組み合わせのインデックス配列があります

##5. 値は混合型をサポートします: array("string",2332)

6. 線形トラバーサルのサポート: foreach

などの Zend ハッシュ テーブルは、典型的なハッシュ テーブルのハッシュ構造を実装し、同時に二重リンク リストをアタッチすることによって配列の前方および逆方向のトラバーサル機能を提供します。その構造は以下のとおりです。

ハッシュ テーブルには、キー -> 値の形式のハッシュ構造と二重リンクの両方が存在することがわかります。リスト モードにより、高速検索と線形トラバースが非常に便利にサポートされます。 PHP の基本的な動作原理の詳細な紹介

1. ハッシュ構造: Zend のハッシュ構造は典型的なハッシュ テーブル モデルであり、リンク リストを通じて競合を解決します。 Zend のハッシュ テーブルは自己成長するデータ構造であることに注意してください。ハッシュ テーブルがいっぱいになると、動的に 2 倍に拡張され、要素の位置が変更されます。初期サイズは8です。さらに、キー->値の高速検索を実行する場合、zend 自体も空間を時間に交換することでプロセスを高速化するいくつかの最適化を行っています。たとえば、変数 nKeyLength は各要素で使用され、キーの長さを識別して迅速に決定します。

2. 二重リンク リスト: 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;

4、PHP索引数组:索引数组就是我们常见的数组,通过下标访问。例如 $arr[0],Zend HashTable内部进行了归一化处理,对于index类型key同样分配了hash值和nKeyLength(为0)。内部成员变量 nNextFreeElement就是当前分配到的最大id,每次push后自动加一。正是这种归一化处理,PHP才能够实现关联和非关联的混合。由于 push操作的特殊性,索引key在PHP数组中先后顺序并不是通过下标大小来决定,而是由push的先后决定。例如 $arr[1] = 2; $arr[2] = 3;对于double类型的key,Zend HashTable会将他当做索引key处理。

六、Hash Table变量

PHP是一门弱类型语言,本身不严格区分变量的类型。PHP在变量申明的时候不需要指定类型。

PHP在程序运行期间可能进行变量类型的隐示转换。 和其他强类型语言一样,程序中也可以进行显示的类型转换。

PHP变量可以分为简单类型(int、string、bool)、集合类型(array resource object)和常量(const)。以上所有的变量在底层都是同一种结构 zval。

Zval主要由三部分组成:

type:指定了变量所述的类型(整数、字符串、数组等)

refcount&is_ref:用来实现引用计数(后面具体介绍)

value:核心部分,存储了变量的实际数据

Zvalue是用来保存一个变量的实际数据。因为要存储多种类型,所以zvalue是一个union,也由此实现了弱类型。

引用计数在内存回收、字符串操作等地方使用非常广泛。PHP中的变量就是引用计数的典型应用。Zval的引用计数通过成员变量is_ref和ref_count实现,通过引用计数,多个变量可以共享同一份数据。避免频繁拷贝带来的大量消耗。在进行赋值操作时,zend将变量指向相同的zval同时ref_count++,在unset操作时,对应的ref_count-1。只有ref_count减为0时才会真正执行销毁操作。如果是引用赋值,则zend会修改is_ref为1。

PHP变量通过引用计数实现变量共享数据,那如果改变其中一个变量值呢?当试图写入一个变量时,Zend若发现该变量指向的zval被多个变量共 享,则为其复制一份ref_count为1的zval,并递减原zval的refcount,这个过程称为“zval分离”。可见,只有在有写操作发生时 zend才进行拷贝操作,因此也叫copy-on-write(写时拷贝)对于引用型变量,其要求和非引用型相反,引用赋值的变量间必须是捆绑的,修改一个变量就修改了所有捆绑变量。整数、浮点数是PHP中的基础类型之一,也是一个简单型变量。对于整数和浮点数,在zvalue中直接存储对应的值。其类型分别是long和double。

从zvalue结构中可以看出,对于整数类型,和c等强类型语言不同,PHP是不区分int、unsigned int、long、long long等类型的,对它来说,整数只有一种类型也就是long。由此,可以看出,在PHP里面,整数的取值范围是由编译器位数来决定而不是固定不变的。

对于浮点数,类似整数,它也不区分float和double而是统一只有double一种类型。在PHP中,如果整数范围越界了怎么办?这种情况下会自动转换为double类型,这个一定要小心,很多trick都是由此产生。

和整数一样,字符变量也是PHP中的基础类型和简单型变量。通过zvalue结构可以看出,在PHP中,字符串是由由指向实际数据的指针和长度结 构体组成,这点和c++中的string比较类似。由于通过一个实际变量表示长度,和c不同,它的字符串可以是2进制数据(包含\0),同时在PHP中, 求字符串长度strlen是O(1)操作。在新增、修改、追加字符串操作时,PHP都会重新分配内存生成新的字符串。最后,出于安全考虑,PHP在生成一个字符串时末尾仍然会添加\0。

常见的字符串拼接方式及速度比较:假设有如下4个变量:$strA=‘123’; $strB = ‘456’; $intA=123; intB=456;

现在对如下的几种字符串拼接方式做一个比较和说明:

$res = $strA.$strB和$res = “$strA$strB”
这种情况下,zend会重新malloc一块内存并进行相应处理,其速度一般
$strA = $strA.$strB
这种是速度最快的,zend会在当前strA基础上直接relloc,避免重复拷贝
$res = $intA.$intB
这种速度较慢,因为需要做隐式的格式转换,实际编写程序中也应该注意尽量避免
$strA = sprintf (“%s%s”,$strA.$strB);
这会是最慢的一种方式,因为sprintf在PHP中并不是一个语言结构,本身对于格式识别和处理就需要耗费比较多时间,另外本身机制

也是malloc内存。不过sprintf的方式最具可读性,实际中可以根据具体情况灵活选择。

PHP的数组通过Zend HashTable来天然实现。foreach操作如何实现?对一个数组的foreach就是通过遍历hashtable中的双向链表完成。对于索引数组,通过foreach遍 历效率比for高很多,省去了key->value的查找。count操作直接调用 HashTable->NumOfElements,O(1)操作。对于’123’这样的字符串,zend会转换为其整数形 式。$arr[‘123’]和$arr[123]是等价的

リソース型変数は、PHP で最も複雑な変数であり、複合構造でもあります。 PHP の zval は幅広いデータ型を表すことができますが、カスタム データ型を完全に記述することは困難です。これらの複合構造を表現する効率的な方法がないため、それらに対して従来の演算子を使用する方法はありません。この問題を解決するには、リソースと呼ばれる本質的に任意の識別子 (ラベル) を介してポインターを参照するだけで済みます。

zval では、リソースの場合、lval はリソースのアドレスを直接指すポインターとして使用されます。リソースは任意の複合構造にすることができ、よく知られた mysqli、fsock、memcached などはすべてリソースです。

リソースの使用方法:

登録: カスタム データ型の場合、それをリソースとして使用します。まず、これを登録する必要があります。そうすれば、zend はそれにグローバルに一意の識別子を割り当てます。

リソース変数の取得: リソースに関して、zend は実際のデータの id->hash_tale を維持します。リソースの場合、その ID のみが zval に記録されます。フェッチするときは、id を通じて hash_table 内の特定の値を検索し、それを返します。

リソースの破棄: リソースのデータ型は多様です。 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 中国語 Web サイトのビデオ チュートリアル: PHP ビデオ チュートリアル

以上がPHP の基本的な動作原理の詳細な紹介の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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