PHP 擴展開發初探

来源:https://www.cnblogs.com/tosser/archive/2019/09/21/11564818.html
-Advertisement-
Play Games

什麼是 PHP 擴展 通俗說,PHP 擴展是增強 PHP 語言功能的插件。PHP 提供了編程語言的語法,比如分支、迴圈、函數、類等,這些是 PHP 本身所提供的。在某些情況下需要在 PHP 語言的基礎上進行擴展,那麼就需要通過 PHP 底層提供的數據結構和介面來開發 PHP 擴展,從而來補充或擴展 ...


什麼是 PHP 擴展

通俗說,PHP 擴展是增強 PHP 語言功能的插件。PHP 提供了編程語言的語法,比如分支、迴圈、函數、類等,這些是 PHP 本身所提供的。在某些情況下需要在 PHP 語言的基礎上進行擴展,那麼就需要通過 PHP 底層提供的數據結構和介面來開發 PHP 擴展,從而來補充或擴展 PHP 語言,使之更加的強大。當然了,PHP 本身就已經集成了一些基本的、強大的、優秀的 PHP 擴展。

 

 

PHP 擴展的好處

從上面的瞭解得知,PHP 擴展可以在 PHP 原有的基礎上來擴展 PHP 的功能,使之更為的強大。另一方面,PHP 擴展可以通過“插件式”的方式來管理和維護 PHP 的功能,如果將全部的功能整合到 PHP 語言中,PHP 想必會過於臃腫,且又不夠靈活。而有了擴展,就解決了這樣的問題。

 

 

PHP 擴展的存在形式

在 Linux 系統下,PHP 擴展以 .so 文件存在,在 Windows 下以 .dll 文件存在。

 

 

什麼時候使用 PHP 擴展

單獨的使用 PHP 語言並不能滿足所有的開發,比如在項目中使用 Redis 或 MongoDB 時,就需要相應的 PHP 擴展,來增強 PHP 語言,讓 PHP 可以來操作 Redis 或者 MongoDB,以完成更加功能強大的項目。

 

 

什麼時候開發自己的 PHP 擴展

開發自己的 PHP 擴展是必須的麽?其實不是。通常情況下,作為一個 PHPer 是不需要自己開發 PHP 擴展的,但是某些情況下可能是必須要開發 PHP 擴展的。比如,我就遇到了這樣的問題。合作的第三方提供了 Windows 下的動態鏈接庫文件(.dll 文件,非 COM 的 DLL 文件),而我又沒有找到如何在 PHP 下載入調用 DLL 文件的方式,因此我需要寫 PHP 擴展,通過 PHP 的擴展來載入和調用第三方提供的 DLL 文件。

 

 

開發自己的 PHP 擴展

在前面我已經提到了我遇到的問題,合作的第三方提供了 Windows 下的動態鏈接庫文件,而我又沒有找到 PHP 下載入和調用 DLL 文件的方式,因此決定自己編寫 PHP 擴展來載入和調用第三方提供的 DLL 文件中的導出函數。以下,就是我對於搭建開發 PHP 擴展環境和編譯 PHP 擴展源碼的記錄。

 

準備工具

首先說明一點,DLL 文件只能在 Windows 系統上運行,Linux 系統上是無法進行運行的。那麼,我們這個擴展是不考慮 Linux 系統的,只考慮 Windows 系統即可。因此,準備的開發工具是 VS2015。起初,我在網上查找了一些資料,很多資料中都寫到,在 Windows 下開發 PHP 擴展需要安裝 CygWin,經過我自己的學習,可以告訴大家“不需要”。當然了,我們的擴展只在 Windows 系統上運行,如果需要在 Linux 系統上運行,是否需要 Cygwin 我就不得而知了。當然了,其他版本的 VS 也應該是可以的,只是我只測試了 VS2015 罷了。

 

下載 PHP 的源代碼

除了需要安裝 VS2015 以外,還需要下載 PHP 的源碼,我下載的源碼是 PHP 7.2 的源碼。

下載 PHP 源碼的地址是:https://windows.php.net/download/

 

打開該地址後,下載如下圖所示的源代碼:

 

在這裡,下載 PHP 7.2 的源碼,並註意在源碼下麵有一個 VC15 x64 的字樣。

 

下載完的的文件為:php-7.2.20-src.zip

下載完源碼進行解壓,解壓後的目錄為:php-7.2.20-src

 

下載源碼並不是一件複雜的事情,但是頁面中有多個版本的源碼可供下載,選擇哪個有時也是比較糾結的問題,這裡就下載 php7.2 的源碼,因為我本地使用的就是 php7.2 的環境。


創建擴展

進入 php-7.2.20-src\ext 目錄下,在該目錄下有一個名為 ext_skel_win32.php 的文件,在命令行中執行:

1 php ext_skel_win32.php --extname=loaddll

其中,loaddll 是要創建的擴展的名稱。想要成功執行該命令,需要將 PHP 的可執行程式添加到環境變數中。

 

執行情況如下:

λ php ext_skel_win32.php --extname=loaddll
Creating directory loaddll
FIND: Parameter format not correct
chmod: missing operand after ‘644’
Try 'chmod --help' for more information.
FIND: Parameter format not correct
chmod: missing operand after ‘755’
Try 'chmod --help' for more information.
Creating basic files: config.m4 config.w32 .gitignore loaddll.c php_loaddll.h CREDITS EXPERIMENTAL tests/001.phpt loaddll.php [done].


To use your new extension, you will have to execute the following steps:


1.  $ cd ..
2.  $ vi ext/loaddll/config.m4
3.  $ ./buildconf
4.  $ ./configure --[with|enable]-loaddll
5.  $ make
6.  $ ./sapi/cli/php -f ext/loaddll/loaddll.php
7.  $ vi ext/loaddll/loaddll.c
8.  $ make


Repeat steps 3-6 until you are satisfied with ext/loaddll/config.m4 and
step 6 confirms that your module is compiled into PHP. Then, start writing
code and repeat the last two steps as often as necessary.

看到如上的輸出提示,則說明我們創建的 PHP 擴展生成成功了。以上輸出如下所示:

此時,在 \ext 目錄下生成了 loaddll 的目錄,該目錄是生成出的 PHP 的擴展模板,可以在模板的基礎上進行開發。

 

使用 VS2015 創建擴展項目

打開 VS2015,我這裡使用的是 VS2015,其他開發環境沒有進行測試。

在 VS2015 中選擇 “文件” -> “新建” -> “從現有代碼創建項目”,來創建 PHP 擴展的解決方案,如下圖:

選擇了 “從現有代碼創建項目” 後,會出現創建項目的嚮導,如下圖:

直接點擊 “下一步”,到如下圖:

在此步驟,選擇剛纔生成的擴展模板的目錄,然後填入項目名稱,這裡是“loaddll”,點擊“下一步”,到達如下圖:

此步驟選擇DLL項目,點擊下一步,到達如下圖:

直接點擊“下一步”,到達如下圖:

點擊“完成”,等待 VS2015 開始創建項目。

 

配置編譯選項並編譯項目

在 VS2015 生成項目完畢後,切換項目為 “Release”和“x64”的選項,如下圖:

切換完成後,在項目上右鍵選擇“屬性”,如下圖:

修改配置類型為 DLL,這樣生成的目標文件擴展名自動變為 .dll,如下圖所示:

選擇“配置屬性” -> “C/C++” -> “常規”,在“附加包含目錄”中點擊“編輯”來添加相關的目錄,如下圖:

這裡需要包含的目錄包括如下圖的幾個目錄:

這裡主要是添加了 PHP 源碼的幾個目錄,因為編譯 PHP 擴展的源碼時需要 PHP 的底層內核數據結構進行支持,因此需要包含以上的目錄。

 

選擇“配置屬性” -> “C/C++” -> “預處理器”,在“預處理器定義”中點擊“編輯”來添加相關預處理指令,如下圖:

在預處理中,HAVE_LOADDLL 中的 LOADDLL 是擴展的名稱,COMPILE_DL_LOADDLL 中的 LOADDLL 同樣也是擴展的名稱,這個名稱與最開始生成擴展模板時的名稱應該一致。

 

編譯源代碼

把 php-7.2.20-src\win32\build\ 目錄下的 config.w32.h.in 複製到 php-7.2.20-src\main\ 目錄下,並重命名為 config.w32.h,這個 .h 文件在編譯時是需要的,但是在 php-7.2.20-src\main\ 下並沒有該文件,因此需要自己手動進行複製。

 

在 config.w32.h 中增加如下代碼

1 #define PHP_COMPILER_ID "VC15" 

註意這裡的 VC15 ,在下載源代碼的時候,我們已經見到過這個標識了。

 

接著,從 PHP 的安裝目錄中複製 php7ts.lib 文件到 loaddll 目錄下,註意,是從PHP 的安裝目錄中,而不是 PHP 源代碼的目錄中。

 

php7ts.lib 在目錄 php7.2.10\dev 目錄下,我使用的是 wamp64 下的 php7.2.10,大家自己使用對應的 .lib 文件即可,當然,這個 .lib 文件也必須是 php7.2 的,因為我們下載的是 php7.2 的源碼。

 

在項目的 resource Files 下添加 php7ts.lib 文件,添加該文件就比較簡單了,同樣是右鍵添加即可。

 

按下 F7 生成解決方案,如圖:

看到“成功 1 個”文件以後,在目錄 \php-7.2.20-src\ext\loaddll\x64\Release 下會生成一個 loaddll.dll 文件,這個文件就是我們的 PHP 擴展文件。

 

PHP 擴展的安裝與測試

將VS2015 生成 loaddll.dll 重命名為 php_loaddll.dll ,將其拷貝到 PHP 環境的擴展中,我的路徑是 php\php7.2.10\ext,想必熟悉 PHP 的應該都會添加 PHP 擴展。如下圖:

在 php.ini 文件中增加配置,如下圖:

使用 php -m 來查看是否有 loaddll.dll 模塊,如下圖:

phpinfo 查看,如下圖:

通過上面可以看出,我們的 PHP 擴展已經正常安裝了,接下來就需要測試我們的擴展是否可以運行了。

 

在 PHP 源碼目錄下 php-7.2.20-src\ext\loaddll\ 有一個 loaddll.php 的測試文件,在命令行下進行執行該命令:

1 php loaddll.php

輸出內容如下:

1 λ php loaddll.php
2 Functions available in the test extension:
3 confirm_loaddll_compiled
4 
5 Congratulations! You have successfully modified ext/loaddll/config.m4. Module loaddll is now compiled into PHP.

如下圖:

看到如上輸出,說明該擴展的模板編譯成功,可以繼續開發實際的擴展模塊了。

 

總結

很多時候,學習編程的第一步就是搭建環境,而往往搭建環境的過程中由於步驟過於複雜,而資料又沒有傻瓜化的詳細步驟,導致很多想要學習或入門的程式員連第一步都無法踏出。對於開發 PHP 擴展而言也是一樣的。

如何通過 PHP 擴展來讓 PHP 程式可以直接調用 DLL 中的函數,除了需要掌握 C 語言的知識以外,還需要掌握 Windows 程式設計的知識,本文就不再討論了,因為有 C 語言的知識和 Windows 程式設計的知識,在 PHP 擴展中調用 DLL 並非難事。

希望本文對大家有所幫助!

 


 

歡迎大家關註微信公眾號:“碼農UP2U”

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 2019-09-21-23:00:26 今天看了很多博客網的博客,看完覺得自己的博客真的是垃圾中的垃圾 新手不知道怎樣寫博客,我也很想寫好一篇能讓人看的博客,但是目前水平不夠 只能慢慢改,今天的博客還是按照自己的方式寫吧,明天開始學習怎麼寫一篇好的博客 但是感覺有點難,加油,但是自己寫博客也是為了記 ...
  • 一、發佈REST服務 二、使用RestTemplae調用服務 三、使用Feign調用服務 ...
  • 新聞 "宣告.NET Core 3.0第一個候選版本" ".NET Core 3.0第一個候選版本中ASP.NET Core與Blazor的更新" "F 的就業市場情形如何" "Finalization實現細節" "GitHub Pages編譯現在使用Checks API" "使用Visual St ...
  • 前言 越來越多的項目已經使用 "Java 8" 了,毫無疑問, "Java 8" 是Java自Java 5(發佈於2004年)之後的最重要的版本。這個版本包含語言、編譯器、庫、工具和 JVM 等方面的十多個新特性。在本文中我們將學習這些新特性,並用實際的例子說明在什麼場景下適合使用。 引用: 本文參 ...
  • 目的:寫給自己看的,不如其他大神全,以後慢慢修修改改 一:如何判斷數據是否垃圾數據 1.引用計數法 當創建一個對象時,為此對象分配一個引用計數器。當有其他對象引用這個對象時,計數器就+1。當引用失效了,計數器-1。 當一個對象的引用計數器=0時,此對象就可以被回收。 優點:原理簡單,實現方便。 缺點 ...
  • AJAX框架Day1 1、Ajax引言 a) 概念 Asynchronous Javascript And XML (非同步請求 javaScript And XML) b) 傳統的請求 2、非同步請求的開發 a) 非同步請求對象的創建 javascript: XmlHttpRequest對象 xhr C ...
  • 本周的 上分享了一篇小文章,它裡面提到的冷知識很有意思,我稍作補充,分享給大家。 它提到的部分問題,讀者們可以先思考下: 若兩個元組相等,即 a==b 且 a is b,那麼相同索引的元素(如 a[0] 、b[0])是否必然相等呢? 若兩個對象的 hash 結果相等,即 hash(a) == has ...
  • JDK(Java Development Kit) JDK顧名思義就是Java開發工具包,是Sun Microsystems針對Java開發員的產品,是Java程式員通過Java語言編寫程式所需的開發工具包,JDK包含了JRE,同時還包含了編譯Java源碼的編輯器Javac,還包含了很多Java程式 ...
一周排行
    -Advertisement-
    Play Games
  • .Net8.0 Blazor Hybird 桌面端 (WPF/Winform) 實測可以完整運行在 win7sp1/win10/win11. 如果用其他工具打包,還可以運行在mac/linux下, 傳送門BlazorHybrid 發佈為無依賴包方式 安裝 WebView2Runtime 1.57 M ...
  • 目錄前言PostgreSql安裝測試額外Nuget安裝Person.cs模擬運行Navicate連postgresql解決方案Garnet為什麼要選擇Garnet而不是RedisRedis不再開源Windows版的Redis是由微軟維護的Windows Redis版本老舊,後續可能不再更新Garne ...
  • C#TMS系統代碼-聯表報表學習 領導被裁了之後很快就有人上任了,幾乎是無縫銜接,很難讓我不想到這早就決定好了。我的職責沒有任何變化。感受下來這個系統封裝程度很高,我只要會調用方法就行。這個系統交付之後不會有太多問題,更多應該是做小需求,有大的開發任務應該也是第二期的事,嗯?怎麼感覺我變成運維了?而 ...
  • 我在隨筆《EAV模型(實體-屬性-值)的設計和低代碼的處理方案(1)》中介紹了一些基本的EAV模型設計知識和基於Winform場景下低代碼(或者說無代碼)的一些實現思路,在本篇隨筆中,我們來分析一下這種針對通用業務,且只需定義就能構建業務模塊存儲和界面的解決方案,其中的數據查詢處理的操作。 ...
  • 對某個遠程伺服器啟用和設置NTP服務(Windows系統) 打開註冊表 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpServer 將 Enabled 的值設置為 1,這將啟用NTP伺服器功 ...
  • title: Django信號與擴展:深入理解與實踐 date: 2024/5/15 22:40:52 updated: 2024/5/15 22:40:52 categories: 後端開發 tags: Django 信號 松耦合 觀察者 擴展 安全 性能 第一部分:Django信號基礎 Djan ...
  • 使用xadmin2遇到的問題&解決 環境配置: 使用的模塊版本: 關聯的包 Django 3.2.15 mysqlclient 2.2.4 xadmin 2.0.1 django-crispy-forms >= 1.6.0 django-import-export >= 0.5.1 django-r ...
  • 今天我打算整點兒不一樣的內容,通過之前學習的TransformerMap和LazyMap鏈,想搞點不一樣的,所以我關註了另外一條鏈DefaultedMap鏈,主要調用鏈為: 調用鏈詳細描述: ObjectInputStream.readObject() DefaultedMap.readObject ...
  • 後端應用級開發者該如何擁抱 AI GC?就是在這樣的一個大的浪潮下,我們的傳統的應用級開發者。我們該如何選擇職業或者是如何去快速轉型,跟上這樣的一個行業的一個浪潮? 0 AI金字塔模型 越往上它的整個難度就是職業機會也好,或者說是整個的這個運作也好,它的難度會越大,然後越往下機會就會越多,所以這是一 ...
  • @Autowired是Spring框架提供的註解,@Resource是Java EE 5規範提供的註解。 @Autowired預設按照類型自動裝配,而@Resource預設按照名稱自動裝配。 @Autowired支持@Qualifier註解來指定裝配哪一個具有相同類型的bean,而@Resourc... ...