PPython:PHP 擁抱 Python 的利器
介紹
Python 與 PHP 都是廣泛使用的語言,各有所長,讓人期待兩者結合可以實現更豐富的效果。
在 PHP 中呼叫 Python 實現某些處理,這種需求雖然比較小眾,還是實用的。目前網上可以查到很多資料仍在探討 exec()
(也包括 system()
、shell_exec()
、passthru()
等)執行外部的 Python 檔案,但這只是一種通用的方式,呼叫成本比較高,在每次呼叫時,需要裝載整個 Python 解釋環境。
有此類需求的開發者非常適合看一下 PPython,這是一種從根本上將 PHP 與 Python 有效結合的技術。
PPython 最初見於 https://code.google.com/p/ppython,該作者將 lajp(一種 PHP 結合 Java 的技術)移植到了 Python 上。
該專案最初建立於 2012 年,而且似乎已經停止維護多年,不過目前來看其思路及效果還是值得肯定的,因此將此專案從停止運營的 Google Code 上遷移到了 GitHub,並遵循原 Apache 許可證重新發布和維護。
日前筆者對此作了一番嘗試,對 PPython 的方便易用有所體會。
原理與架構
PHP 與 Python 通訊有兩種不同的套接字機制:TCP 套接字和 UNIX 套接字。UNIX 套接字是 Unix/Linux 本地套接字,相對於 TCP 套接字,具有以下特點:
- 只能在同一臺主機中通訊(IPC),不能跨主機;
- 傳輸速度大於 TCP 套接字;
- 服務端只向本機提供服務(沒有對外偵聽埠),相對安全,易於管理。
PHP 和 Python 各有其語言內部定義的資料型別,通常 PHP 程式與 Python 程式進行資料互動時,需要進行轉碼處理。此類轉換如由應用自行實現,從開發效率到執行效能都會增加不少額外負擔。
PPython 對 PHP 和 Python 間的通訊方式的處理支援 TCP 套接字和 UNIX 套接字兩種機制,兼顧通訊效率和分散式,轉碼由服務統一處理,Python 為 PHP 的資料型別提供格式相容,使 PHP 端開發無須為底層通訊擔心。
Python 因其語言 GIL 特性,同一程式內多執行緒效率不高。PPython 可根據專案需要部署服務,多程式執行 Python,提高應用綜合效能。
使用方法
PPython 的程式碼可從上述專案倉庫中下載。
下載得到的檔案中,以下三個是 PPython 的核心程式碼,作用如下:
php_python.py
,Python 程式主檔案,完成 Python 端監聽請求並執行返回process.py
,Python 端核心類,實現 Python 內部程式呼叫及 PHP 與 Python 資料結構轉化等關鍵處理php_python.php
,PPython 客戶端,PHP 端引用此檔案,可直接使用 PPython 函式實現呼叫。
將以上檔案放置到任意目錄。先修改準備執行 PPython 的埠,監聽埠不限,只要 php_python.py
和 php_python.php
兩端修改一致。筆者統一改為 10240。
在當前目錄下執行 php_python.py
,只要 Python 環境正常,便將執行起一個 PPython 的服務。
-------------------------------------------
- PPython Service
- Time: 2019-05-13 22:24:09
-------------------------------------------
Listen port: 10240
charset: utf-8
Server startup...
PHP 端引入 php_python.php
,就可以用 ppython
函式與之前啟動的 PPython 服務通訊,傳入請求由 PPython 服務呼叫 Python 處理後返回結果,如 $res = ppython('test::go')
是呼叫test.py
中的 go
函式,也可加上更多引數,第二個引數起將為被調的函式傳遞更多引數。
php_python.py
是 PPython 啟動後直接執行的全域性程式碼,有全域性配置或程式啟動後的通用處理都寫在這裡,如原生程式碼中建立了資料庫連線等,專案中應視情況作優化。
但 Python 令人感興趣的主要方面不只是像 PHP 那樣描述業務功能,它可以在人工智慧等領域所需要的計算型任務提供對更復雜的資料結構的處理,因此二者的結合可以給 PHP 帶來更多應用場景。
改進
此外,原生的 php_python.py
還有些不足。筆者用 ppython
呼叫自定義程式碼中遇到了三個問題,並相應做了解決:
-
不支援
complex
(複數類),複數是數學上的一種資料型別,主要包括real
(實部)和imag
(虛部)資料,雖然日常生活中遇到較少,但 AI 和各種專業研究領域或並不罕見。Python 裡有complex
類,對複數可以直接進行各種計算,但PPython
序列化和反序列化對complex
沒有處理。為了能讓complex
包括的資料能正常返回,只要在process.py
的z_encode()
方法中加上符合 PHP 要求的序列化處理,程式碼如下:elif isinstance(p, numpy.complex128): t1 = str(p.real) t2 = str(p.imag) return 'O:7:"complex":2:{s:4:"real";d:%s;s:4:"imag";d:%s;}' % (t1,t2)
-
不支援
ndarray
(多維陣列)。相比complex
,ndarray
要普通得多,相信凡使用到 Python 的各種計算功能,ndarray
是無法迴避的,甚至ndarray
在一定程度上成就了 Python。但原php_python.py
不能識別ndarray
。不過解決起來並不難,在process.py
裡找到z_encode()
方法,加上下面這段,可以直接將ndarray
轉化為符合 PHP 要求的陣列(數字索引)。elif isinstance(p, numpy.ndarray): s = '' i = 0 for d in p: s += 'i:%d;%s' % (i,z_encode(d)) i += 1 return "a:%d:{%s}" % (len(p),s)
-
原始碼不太穩健,如資料為
ndarray
型別,if p == None:
報錯ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
,因為p == None
的結果也是ndarray
,不返回false
,將判斷方法改為if p is None:
可避免出錯。相應地 PHP 端也要注意一下序列化和反序列化的處理。
處理回覆中類似 complex
這樣的物件資料時,如系統中沒有定義相應的類,PHP 是可以反序列化的,但將顯示為 “incomplete object”,vardump
看得到 real
和 imag
資料,但不能直接操作,自行定義 complex
類後,則按指定的類進行解析,與 PHP 內的一般物件無異,可以輕鬆進行所有操作。
至此,PHP 與 Python 的功能調訊已無問題。
補充:註冊為服務
命令列下啟動 php_python.py
主要是方便除錯,可以看到觀察反饋資訊等,生產環境中手工啟動 PPython 畢竟不太方便。可以將 PPython 配置成服務,修改埠也可以為不同的應用配置不同的 PPython 端。
Linux 下將一個程式註冊為服務很簡單,只要建立 /usr/lib/systemd/system/ppython.service
,內容如下:
[Unit]
Description=PHP-Python Service
After=network.target remote-fs.target nss-lookup.target
[Service]
ExecStart={PPYTHON_PATH}/php_python.py
[Install]
WantedBy=multi-user.target
其中 {PPYTHON_PATH}
要改成實際路徑。
總結
有了 PPython,可以摒棄 exec()
這種 shell 呼叫,使開發迴歸到邏輯本身。
個人認為該方案值得所有對 PHP 和 Python 都感興趣的開發人員瞭解,也歡迎大家參與和貢獻這個專案。
相關文章
- 擁抱雲原生,Fluid 結合 JindoFS:阿里雲 OSS 加速利器UI阿里
- 擁抱 React HooksReactHook
- 金融擁抱區塊鏈區塊鏈
- 擁抱錯誤與嘗試
- 擁抱模式化未來模式
- 跳出任務管理的泥沼,擁抱甘特圖的懷抱(完整版)
- Omi 擁抱 60FPS 的 Web 動畫Web動畫
- 擁抱正版免費的jetbrain IDE EAP版AIIDE
- 你所需要擁抱的TypeScript [技術貼]TypeScript
- Java NIO之擁抱Path和FilesJava
- Artix : Arch擁抱OpenRC 使用筆記筆記
- SRE方法論之擁抱風險
- 拋棄os.path,擁抱pathlib
- 擁抱Spring全新OAuth解決方案SpringOAuth
- 擁抱未來,Meta 奔向「元宇宙」元宇宙
- 擁抱 JSX,它是一個偉大的嘗試JS
- 性感的Promise,擁抱ta然後扒光taPromise
- 扔掉 Electron,擁抱基於 Rust 開發的 TauriRust
- 2023~某熊的成長之路:擁抱更大的世界
- Apache Kyuubi & Celeborn,助力 Spark 擁抱雲原生ApacheSpark
- Spring Boot 把 Maven 幹掉了,擁抱 Gradle!Spring BootMavenGradle
- 擁抱react新生命週期–getDerivedStateFromPropsReact
- 擁抱 OpenAPI 3:springdoc-openapi 食用指南APISpring
- 團隊文化建設:擁抱黑客文化黑客
- 做個清醒的程式設計師之擁抱AI程式設計師AI
- .NET 9 的新亮點:AI就緒 ,擁抱她AI
- 擁抱開放,Serverless 時代的下一征程Server
- 擁抱智慧,AI 影片編碼技術的新探索AI
- 【劉文彬】區塊鏈3.0:擁抱EOS區塊鏈
- 擁抱智慧,IT運維將有哪些變化?運維
- Rollup作者新作: Svelte Cubed, 擁抱 Three.js !JS
- ModStart:擁抱新技術,率先支援 Laravel 9.0Laravel
- 擁抱Spring全新OAuth2解決方案SpringOAuth
- Ppython await是什麼?PythonAI
- 全場景智慧:新工業革命必須擁抱的晨曦
- 讓我放棄FastDFS擁抱MinIO的8個瞬間AST
- 擁抱智慧,AI 視訊編碼技術的新探索AI
- php效能分析利器:xhprofPHP