當 PHP 專案需要:
PHP Java Bridge (PJB) 提供了在 PHP 進程內嵌入 JVM、雙向調用的橋樑。
┌─────────────┐ JNI / Socket ┌─────────────┐ │ PHP Process │ ◄──────────────────► │ JVM Process │ │ (Apache/ │ PHP-Java Bridge │ (Java Libs │ │ PHP-FPM) │ (php_java.dll/ │ + Bridge) │ └─────────────┘ .so) └─────────────┘
兩種通訊模式:
php_java.dll),延遲低但風險高(JVM Crash 導致 PHP 進程崩潰)JAVA_HOME、PATH 包含 %JAVA_HOME%\bin[java] extension=php_java.dll java.home = "C:/Program Files/Java/jdk-17" java.library = "C:/Program Files/Java/jdk-17/bin/server/jvm.dll" java.library.path = "C:/php/ext" java.class.path = "C:/php/ext/php_java.jar;C:/java-bridge/lib/*;C:/my-java-libs/*" ; 生產環境建議 Servlet 模式,不需上述配置,改用: ; java.host = 127.0.0.1 ; java.port = 8080 ; java.servlet = On
JavaBridge.war(SourceForge php-java-bridge 專案)webapps/JavaBridge.warhttps://localhost:8080/JavaBridge/ 驗證[java] extension=php_java.dll java.host = 127.0.0.1 java.port = 8080 java.servlet = On java.context = /JavaBridge
<?php
// 測試連線
$system = new Java('java.lang.System');
echo "Java 版本: " . $system->getProperty('java.version') . "<br>";
echo "廠商: " . $system->getProperty('java.vendor') . "<br>";
echo "OS: " . $system->getProperty('os.name') . " " . $system->getProperty('os.version') . "<br>";
// 日期格式化
$formatter = new Java('java.text.SimpleDateFormat', 'yyyy-MM-dd HH:mm:ss z');
echo "當前時間: " . $formatter->format(new Java('java.util.Date')) . "<br>";
// 使用自定義類(需在 java.class.path 中)
try {
$myUtil = new Java('com.mycompany.utils.StringUtils');
$result = $myUtil->encrypt('sensitive-data', 'AES/ECB/PKCS5Padding');
echo "加密結果: $result";
} catch (JavaException $e) {
echo "Java 異常: " . $e->getMessage();
}
?>
<?php
// PHP 陣列 → Java List
$phpArray = ['apple', 'banana', 'orange'];
$javaList = new Java('java.util.ArrayList');
foreach ($phpArray as $item) {
$javaList->add($item);
}
// Java List → PHP 陣列
$javaArrayList = $someJavaObj->getStringList();
$phpArray = [];
for ($i = 0; $i < $javaArrayList->size(); $i++) {
$phpArray[] = $javaArrayList->get($i);
}
// Java Map ↔ PHP 關聯陣列
$javaMap = new Java('java.util.HashMap');
$javaMap->put('key1', 'value1');
$javaMap->put('key2', 123);
// 遍歷
$iterator = $javaMap->entrySet()->iterator();
while ($iterator->hasNext()) {
$entry = $iterator->next();
echo $entry->getKey() . ' = ' . $entry->getValue() . "<br>";
}
?>
<?php
try {
$obj = new Java('com.example.RiskyClass');
$obj->dangerousMethod();
} catch (JavaException $e) {
// Java 異常包裝為 PHP 異常
error_log("Java Error: {$e->getMessage()}\nStack: {$e->getTraceAsString()}");
// 可獲取 Java 異常類名
echo "Java 異常類: " . $e->getJavaClassName();
} catch (Exception $e) {
// PHP 端異常(如類不存在、通訊失敗)
error_log("PHP Error: {$e->getMessage()}");
}
?>
| 現象 | 原因 | 解決 |
|---|---|---|
| UnsatisfiedLinkError: php_java.dll | DLL 版本不匹配(PHP 版本/TS-NTS/VC 版本/位數) | 下載匹配版本,或改用 Servlet 模式 |
| ClassNotFoundException | java.class.path 缺少對應 JAR/目錄 | 檢查路徑、確認 JAR 完整、重啟 Tomcat/PHP |
| Java heap space / OOM | JVM 記憶體不足 | 調整 Tomcat JAVA_OPTS=-Xms512m -Xmx2g |
| PHP 進程崩潰 (Segmentation fault) | 內嵌模式下 JNI 錯誤導致 | 強制遷移至 Servlet 模式隔離進程 |
| 中文亂碼 | 編碼不一致 | 確保 Java 端 -Dfile.encoding=UTF-8,PHP 端 mb_internal_encoding('UTF-8') |
| 方案 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| PHP-Java Bridge | 無縫調用、支援複雜物件、雙向 | 部署複雜、穩定性依賴 JVM、效能開銷 | 深度整合、複用大量 Java 邏輯 |
| REST/gRPC API | 解耦、語言無關、可擴展、雲原生 | 網路延遲、需維護介面契約 | 微服務架構、跨團隊協作 |
| 命令行調用 (exec/shell) | 極簡單、完全隔離 | 啟動開銷大、難傳複雜資料、安全風險 | 偶發性任務、腳本封裝 |
| JPHP / Quercus | 在 JVM 上運行 PHP | 生態不兼容、維護狀態不確定 | 遷移專案、特殊需求 |
建議:現代架構優先考慮 REST/gRPC 微服務,將 Java 能力封裝為獨立服務。僅在遷移期、極強耦合場景、或無法拆分服務時使用 PHP-Java Bridge。生產環境務必使用 Servlet 模式隔離進程,並建立完善監控(JVM 指標、Bridge 連線池狀態、調用延遲/錯誤率)。