mirror of
				https://github.com/yiisoft/yii2.git
				synced 2025-10-31 02:28:35 +08:00 
			
		
		
		
	Fix #20348: ErrorHandler::convertExceptionToError() Passing E_USER_ERROR to trigger_error() is deprecated since PHP 8.4
				
					
				
			This commit is contained in:
		| @ -26,6 +26,7 @@ Yii Framework 2 Change Log | |||||||
| - Enh #20413: Add PHPStan/Psalm annotations for `Action`, `ActionEvent`, `Application`, `DynamicModel` and `InlineAction` (max-s-lab) | - Enh #20413: Add PHPStan/Psalm annotations for `Action`, `ActionEvent`, `Application`, `DynamicModel` and `InlineAction` (max-s-lab) | ||||||
| - Enh #20416: Add `PHPStan`/`PSalm` annotation for `owner` property in `Behavior` class (terabytesoftw) | - Enh #20416: Add `PHPStan`/`PSalm` annotation for `owner` property in `Behavior` class (terabytesoftw) | ||||||
| - Bug #20423: `strcmp()` Passing `null` to parameter `2` ($string2) of type string is deprecated (terabytesoftw) | - Bug #20423: `strcmp()` Passing `null` to parameter `2` ($string2) of type string is deprecated (terabytesoftw) | ||||||
|  | - Bug #20348: `ErrorHandler::convertExceptionToError()` Passing `E_USER_ERROR` to `trigger_error()` is deprecated since PHP `8.4` (terabytesoftw) | ||||||
|  |  | ||||||
|  |  | ||||||
| 2.0.52 February 13, 2025 | 2.0.52 February 13, 2025 | ||||||
|  | |||||||
| @ -51,6 +51,41 @@ if you want to upgrade from version A to version C and there is | |||||||
| version B between A and C, you need to follow the instructions | version B between A and C, you need to follow the instructions | ||||||
| for both A and B. | for both A and B. | ||||||
|  |  | ||||||
|  | Upgrade from Yii 2.0.53 | ||||||
|  | ----------------------- | ||||||
|  |  | ||||||
|  | * `ErrorHandler::convertExceptionToError()` has been deprecated and will be removed in version 22.0. | ||||||
|  |  | ||||||
|  |   This method was deprecated due to `PHP 8.4` deprecating the use of `E_USER_ERROR` with `trigger_error()`. | ||||||
|  |   The framework now handles exceptions in `__toString()` methods more appropriately based on the PHP version. | ||||||
|  |  | ||||||
|  |   **Before (deprecated):** | ||||||
|  |   ```php | ||||||
|  |   public function __toString() { | ||||||
|  |       try { | ||||||
|  |           return $this->render(); | ||||||
|  |       } catch (\Throwable $e) { | ||||||
|  |           ErrorHandler::convertExceptionToError($e); | ||||||
|  |           return ''; | ||||||
|  |       } | ||||||
|  |   } | ||||||
|  |   ``` | ||||||
|  |  | ||||||
|  |   **After (recommended):** | ||||||
|  |   ```php | ||||||
|  |   public function __toString() { | ||||||
|  |       try { | ||||||
|  |           return $this->render(); | ||||||
|  |       } catch (\Throwable $e) { | ||||||
|  |           if (PHP_VERSION_ID < 70400) { | ||||||
|  |               trigger_error(ErrorHandler::convertExceptionToString($e), E_USER_ERROR); | ||||||
|  |               return ''; | ||||||
|  |           } | ||||||
|  |           throw $e; | ||||||
|  |       } | ||||||
|  |   } | ||||||
|  |   ``` | ||||||
|  |  | ||||||
| Upgrade from Yii 2.0.52 | Upgrade from Yii 2.0.52 | ||||||
| ----------------------- | ----------------------- | ||||||
| * There was a bug when loading fixtures into PostgreSQL database, the table sequences were not reset. If you used a work-around or if you depended on this behavior, you are advised to review your code. | * There was a bug when loading fixtures into PostgreSQL database, the table sequences were not reset. If you used a work-around or if you depended on this behavior, you are advised to review your code. | ||||||
|  | |||||||
| @ -378,6 +378,11 @@ abstract class ErrorHandler extends Component | |||||||
|      * to PHP errors because exceptions cannot be thrown inside of them. |      * to PHP errors because exceptions cannot be thrown inside of them. | ||||||
|      * @param \Throwable $exception the exception to convert to a PHP error. |      * @param \Throwable $exception the exception to convert to a PHP error. | ||||||
|      * @return never |      * @return never | ||||||
|  |      * | ||||||
|  |      * @deprecated since 2.0.53. Use conditional exception throwing in `__toString()` methods instead. | ||||||
|  |      * For PHP < 7.4: use `trigger_error()` directly with `convertExceptionToString()` method. | ||||||
|  |      * For PHP >= 7.4: throw the exception directly as `__toString()` supports exceptions. | ||||||
|  |      * This method will be removed in 2.2.0. | ||||||
|      */ |      */ | ||||||
|     public static function convertExceptionToError($exception) |     public static function convertExceptionToError($exception) | ||||||
|     { |     { | ||||||
|  | |||||||
| @ -59,9 +59,14 @@ abstract class BaseMessage extends BaseObject implements MessageInterface | |||||||
|         // use trigger_error to bypass this limitation |         // use trigger_error to bypass this limitation | ||||||
|         try { |         try { | ||||||
|             return $this->toString(); |             return $this->toString(); | ||||||
|         } catch (\Exception $e) { |         } catch (\Throwable $e) { | ||||||
|             ErrorHandler::convertExceptionToError($e); |             if (PHP_VERSION_ID < 70400) { | ||||||
|  |                 trigger_error(ErrorHandler::convertExceptionToString($e), E_USER_ERROR); | ||||||
|  |  | ||||||
|                 return ''; |                 return ''; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  |             throw $e; | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -174,13 +174,15 @@ class ActiveField extends Component | |||||||
|         // use trigger_error to bypass this limitation |         // use trigger_error to bypass this limitation | ||||||
|         try { |         try { | ||||||
|             return $this->render(); |             return $this->render(); | ||||||
|         } catch (\Exception $e) { |  | ||||||
|             ErrorHandler::convertExceptionToError($e); |  | ||||||
|             return ''; |  | ||||||
|         } catch (\Throwable $e) { |         } catch (\Throwable $e) { | ||||||
|             ErrorHandler::convertExceptionToError($e); |             if (PHP_VERSION_ID < 70400) { | ||||||
|  |                 trigger_error(ErrorHandler::convertExceptionToString($e), E_USER_ERROR); | ||||||
|  |  | ||||||
|                 return ''; |                 return ''; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  |             throw $e; | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|  | |||||||
| @ -60,6 +60,54 @@ class BaseMessageTest extends TestCase | |||||||
|         $message = $mailer->compose(); |         $message = $mailer->compose(); | ||||||
|         $this->assertEquals($message->toString(), '' . $message); |         $this->assertEquals($message->toString(), '' . $message); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public function testExceptionToString() | ||||||
|  |     { | ||||||
|  |         if (PHP_VERSION_ID < 70400) { | ||||||
|  |             $this->markTestSkipped('This test is for PHP 7.4+ only'); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $message = new TestMessageWithException(); | ||||||
|  |  | ||||||
|  |         $this->expectException(\Exception::class); | ||||||
|  |         $this->expectExceptionMessage('Test exception in toString.'); | ||||||
|  |  | ||||||
|  |         (string) $message; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testExceptionToStringLegacy() | ||||||
|  |     { | ||||||
|  |         if (PHP_VERSION_ID >= 70400) { | ||||||
|  |             $this->markTestSkipped('This test is for PHP < 7.4 only'); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $message = new TestMessageWithException(); | ||||||
|  |  | ||||||
|  |         $errorTriggered = false; | ||||||
|  |         $errorMessage = ''; | ||||||
|  |  | ||||||
|  |         set_error_handler( | ||||||
|  |             function ($severity, $message, $file, $line) use (&$errorTriggered, &$errorMessage) { | ||||||
|  |                 if ($severity === E_USER_ERROR) { | ||||||
|  |                     $errorTriggered = true; | ||||||
|  |                     $errorMessage = $message; | ||||||
|  |  | ||||||
|  |                     return true; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 return false; | ||||||
|  |             }, | ||||||
|  |             E_USER_ERROR, | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         $result = (string) $message; | ||||||
|  |  | ||||||
|  |         restore_error_handler(); | ||||||
|  |  | ||||||
|  |         $this->assertTrue($errorTriggered, 'E_USER_ERROR should have been triggered'); | ||||||
|  |         $this->assertStringContainsString('Test exception in toString.', $errorMessage); | ||||||
|  |         $this->assertSame('', $result, 'Result should be an empty string'); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @ -178,3 +226,11 @@ class TestMessage extends BaseMessage | |||||||
|         return get_class($this); |         return get_class($this); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | class TestMessageWithException extends TestMessage | ||||||
|  | { | ||||||
|  |     public function toString() | ||||||
|  |     { | ||||||
|  |         throw new \Exception('Test exception in toString.'); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | |||||||
| @ -700,6 +700,54 @@ HTML; | |||||||
|         $this->assertStringContainsString('placeholder="pholder_both_direct"', (string) $widget); |         $this->assertStringContainsString('placeholder="pholder_both_direct"', (string) $widget); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public function testExceptionToString() | ||||||
|  |     { | ||||||
|  |         if (PHP_VERSION_ID < 70400) { | ||||||
|  |             $this->markTestSkipped('This test is for PHP 7.4+ only'); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $field = new TestActiveFieldWithException(); | ||||||
|  |  | ||||||
|  |         $this->expectException(\Exception::class); | ||||||
|  |         $this->expectExceptionMessage('Test exception in toString.'); | ||||||
|  |  | ||||||
|  |         (string) $field; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testExceptionToStringLegacy() | ||||||
|  |     { | ||||||
|  |         if (PHP_VERSION_ID >= 70400) { | ||||||
|  |             $this->markTestSkipped('This test is for PHP < 7.4 only'); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $field = new TestActiveFieldWithException(); | ||||||
|  |  | ||||||
|  |         $errorTriggered = false; | ||||||
|  |         $errorMessage = ''; | ||||||
|  |  | ||||||
|  |         set_error_handler( | ||||||
|  |             function ($severity, $message, $file, $line) use (&$errorTriggered, &$errorMessage) { | ||||||
|  |                 if ($severity === E_USER_ERROR) { | ||||||
|  |                     $errorTriggered = true; | ||||||
|  |                     $errorMessage = $message; | ||||||
|  |  | ||||||
|  |                     return true; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 return false; | ||||||
|  |             }, | ||||||
|  |             E_USER_ERROR, | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         $result = (string) $field; | ||||||
|  |  | ||||||
|  |         restore_error_handler(); | ||||||
|  |  | ||||||
|  |         $this->assertTrue($errorTriggered, 'E_USER_ERROR should have been triggered'); | ||||||
|  |         $this->assertStringContainsString('Test exception in toString.', $errorMessage); | ||||||
|  |         $this->assertSame('', $result, 'Result should be an empty string'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Helper methods. |      * Helper methods. | ||||||
|      */ |      */ | ||||||
| @ -811,3 +859,11 @@ class TestMaskedInput extends MaskedInput | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | class TestActiveFieldWithException extends ActiveField | ||||||
|  | { | ||||||
|  |     public function render($content = null) | ||||||
|  |     { | ||||||
|  |         throw new \Exception('Test exception in toString.'); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 Wilmer Arambula
					Wilmer Arambula