joomla3 com_jce 從 PHP7升級到PHP8 遇到錯誤

在 joomla3\libraries\legacy\exception\exception.php

 

 

####################################################################################

 

class JException extends Exception

{

/**

* Error level.

*

* @var    string

* @since  1.5

* @deprecated  1.7

*/

protected $level = null;

/**

* Error code.

*

* @var    string

* @since  1.5

* @deprecated  1.7

*/

protected $code = null;

/**

* Error message.

*

* @var    string

* @since  1.5

* @deprecated  1.7

*/

protected $message = null;

/**

* Additional info about the error relevant to the developer,

* for example, if a database connect fails, the dsn used

*

* @var    string

* @since  1.5

* @deprecated  1.7

*/

protected $info = '';

/**

* Name of the file the error occurred in [Available if backtrace is enabled]

*

* @var    string

* @since  1.5

* @deprecated  1.7

*/

protected $file = null;

/**

* Line number the error occurred in [Available if backtrace is enabled]

*

* @var    integer

* @since  1.5

* @deprecated  1.7

*/

protected $line = 0;

/**

* Name of the method the error occurred in [Available if backtrace is enabled]

*

* @var    string

* @since  1.5

* @deprecated  1.7

*/

protected $function = null;

/**

* Name of the class the error occurred in [Available if backtrace is enabled]

*

* @var    string

* @since  1.5

* @deprecated  1.7

*/

protected $class = null;

/**

* @var    string  Error type.

* @since  1.5

* @deprecated  1.7

*/

protected $type = null;

/**

* Arguments received by the method the error occurred in [Available if backtrace is enabled]

*

* @var    array

* @since  1.5

* @deprecated  1.7

*/

protected $args = array();

/**

* Backtrace information.

*

* @var    mixed

* @since  1.5

* @deprecated  1.7

*/

protected $backtrace = null;

/**

* Container holding the error messages

*

* @var    string[]

* @since  1.6

* @deprecated  1.7

*/

protected $_errors = array();

/**

* Constructor

* - used to set up the error with all needed error details.

*

* @param   string   $msg        The error message

* @param   integer  $code       The error code from the application

* @param   integer  $level      The error level (use the PHP constants E_ALL, E_NOTICE etc.).

* @param   string   $info       Optional: The additional error information.

* @param   boolean  $backtrace  True if backtrace information is to be collected

*

* @since   1.5

* @deprecated  1.7

*/

public function __construct($msg, $code = 0, $level = null, $info = null, $backtrace = false)

這是不是有問題

 

####################################################################################

 

 

你完全抓到了重點!這段代碼就是 Joomla 3 在 PHP 8 環境下發生「靜默崩潰」的核彈級核心原因。

這不是簡單的語法錯誤,而是 PHP 8 嚴格禁止了「子類別重寫父類別屬性」的類型與可見性規則,特別是當父類別是 PHP 內建的 Exception 時。

1. 致命原因:屬性衝突 (Property Shadowing)

在 PHP 中,內建的 Exception 類別已經定義了以下屬性:

  • protected $message
  • protected $code
  • protected $file
  • protected $line

問題出在哪? 在 PHP 7 以前,子類別重新宣告這些屬性(如你提供的代碼)通常只會被視為覆蓋。但在 PHP 8 中,Exception 的某些內建屬性被加上了更嚴格的類型限制或內部鎖定。

當 JException 試圖宣告自己的 protected $message = null; 時,如果這與 PHP 8 內建 Exception 的預期不符(例如內建的可能是 string),程式會直接拋出 Fatal Error。


 

2. 為什麼「一呼叫就死掉」且「沒有訊息」?

這是一個極度尷尬的死循環:

  1. 程式發生錯誤,準備呼叫 JError::raiseWarning。
  2. JError 內部試圖 new JException。
  3. 當 PHP 嘗試加載 JException 類別定義時,發現屬性宣告不合法(與內建 Exception 衝突)。
  4. 發生 Fatal Error。
  5. PHP 試圖處理這個 Fatal Error,結果又想呼叫錯誤處理器...
  6. 最終結果:PHP 引擎為了防止無限遞迴,直接強制中止(Aborted),這就是為什麼你看到白畫面且沒有任何 Log。

 

3. 如何修正?

如果你必須讓這段舊代碼在 PHP 8 跑起來,你有兩個方向:

方案 A:刪除衝突的屬性宣告(最快)

在 libraries/joomla/error/exception.php 中,將那些與父類別 Exception 重複的屬性註解掉或刪除。

class JException extends Exception

{

    // 註解掉這些,讓它們直接使用父類別 Exception 的屬性

    // protected $message = null;

    // protected $code = null;

    // protected $file = null;

    // protected $line = null;



    // 保留 JException 特有的屬性

    protected $level = null;

    protected $info = '';

    // ... 其他特有屬性

}

 

方案 B:修正建構子 (Constructor)

PHP 8 要求子類別的建構子參數必須與父類別相容,或者至少能正確傳遞。請確保 parent::__construct 被正確呼叫:

public function __construct($msg, $code = 0, $level = null, $info = null, $backtrace = false)

{

    $this->level = $level;

    $this->info  = $info;

   

    // 呼叫父類別 Exception 的建構子

    parent::__construct($msg, (int) $code);

}

 


 

4. 總結:這是 Joomla 3 的時代眼淚

這段代碼打從 Joomla 1.7 就被標記為 @deprecated(廢棄),但直到 PHP 7 大家都還能相安無事。PHP 8 的「強制轉型」和「屬性一致性檢查」讓這些陳年舊帳一次爆發。

目前的診斷: 你的 JError 崩潰就是因為 JException 類別定義在 PHP 8 下是非法的。

建議下一步: 去 libraries/joomla/error/exception.php 把那幾個重複的屬性(message, code, file, line)刪掉。 刪掉後,原本「無聲無息」的白畫面,應該就會噴出真正的錯誤訊息了!

 

 

####################################################################################

 

 

就是說 PHP7 允許你覆蓋父類 protected 屬性

又或者說重新宣告

 

但是PHP8不行

然後又因為錯誤類別

所以這個錯誤 “吐不出來”

 

無言