rfc:assert-string-eval-cleanup

PHP RFC: Deprecate remains of string evaluated code assertions

Introduction

Prior to PHP 7 assertions via the assert function could only operate on boolean values or with strings, in which case the string was evaluated and the result of it would be interpreted. The behaviour used by assert() is dependent on various INI settings that can also be set using the assert_options() function.

PHP 7 introduced “Expectations” which work with arbitrary expressions without needing to use eval() internally by utilizing the newly introduced AST. To preserve backwards compatibility, none of the previous assert INI settings were removed to allow the usage of “legacy” code assertions while migrating to the expression based one. In doing so, 2 new INI settings were introduced, zend_assertions and assert.exception.

Moreover, the “legacy” code assertions were deprecated in PHP 7.2 and have been removed in PHP 8.0. However, only the assert.quiet_eval INI setting and corresponding ASSERT_QUIET_EVAL have been removed. None of the other INI settings related to those assertions had been deprecated nor removed. Moreover, with the removal of the code assertions in PHP 8.0 some subtle behavioural changes were made if one continues to use the legacy INI settings.

Thus, the proposal is to deprecate those INI settings, the assert_options() function that allows to set them, and the relevant ASSERT_* constants.

The INI settings and constants in question are:

  • assert.active and ASSERT_ACTIVE
  • assert.warning and ASSERT_WARNING
  • assert.bail and ASSERT_BAIL
  • assert.callback and ASSERT_CALLBACK
  • assert.exception and ASSERT_EXCEPTION which were introduced in PHP 7.0

We will now explain what each of these settings does:

assert.active

Enabled by default. If disabled, any call to the assert() function will immediately return true. Otherwise, the assertion is executed.

assert.warning

Enabled by default. If enabled, a warning is emitted if an assertion fails. As of PHP 7, this setting only has an effect if assert.exception is disabled.

assert.bail

Disabled by default. If enabled, the engine bails out when an assertion fails. One needs to remember that prior to PHP 7, the engine didn't throw exceptions and thus this was the only way to abort execution on assertion failure.

assert.callback

null by default. This setting allows defining a function (as a string) that should be called when an assertion fails. The only way to assign a more generic callable (e.g. an object having an __invoke() magic method) is by using the assert_options() function.

assert.exception

Enabled by default. If enabled, an AssertionError or a custom exception is thrown if an assertion fails.

Behavioural changes between PHP 7 and 8

With the removal of the string evaluated assertion in PHP, some unintended behavioural changes were made.

Providing a custom exception short-circuits assert()

As of PHP 8.0, if a custom exception to be thrown is passed as a second argument to assert() the only INI setting that has any effect is assert.active, because if the assertion fails the custom exception is immediately thrown.

Moreover, the potentially set callback is not called.

Signature change of the assertion callback

In PHP 7 and previously, the assertion callback signature was as follows:

fn (string $filename, int $line_number, string $code, string $description = ?)

Where $code represents the string evaluated assertion if provided or an empty string.

As of PHP 8.0, the signature of the callback is as follows:

fn (string $filename, int $line_number, null $code, string $description = ?)

Because the assert() function now always provides null instead of an empty string for the code argument.

Formal Proposal

  • Formally deprecate the assert_options() function that was “soft deprecated” in PHP 7.0, by emitting an E_DEPRECATED notice when it is called.
  • Deprecate the assert.active INI setting and ASSERT_ACTIVE constant, the zend_assertions INI setting has superseded it for a while.
  • Deprecate the assert.warning INI setting and ASSERT_WARNING constant
  • Deprecate the assert.bail INI setting and ASSERT_BAIL constant
  • Deprecate the assert.callback INI setting and ASSERT_CALLBACK constant, thus deprecating this feature completely.
  • Deprecate the assert.exception INI setting and ASSERT_EXCEPTION constant
  • Change the return value of assert() from bool to void when those features have been removed

The behaviour of a deprecated INI setting is as follows:

A deprecation notice is only emitted if the value set in an INI file, or at runtime via ini_set() differs from its default value.

Proposed PHP Version

Next minor version, i.e. PHP 8.3.

Proposed Voting Choices

As per the voting RFC a yes/no vote with a 2/3 majority is needed for this proposal to be accepted.

Voting started on 2023-06-28 and will end on 2023-07-12.

Accept Deprecate remains of string evaluated code assertions RFC?
Real name Yes No
alcaeus (alcaeus)  
ashnazg (ashnazg)  
brzuchal (brzuchal)  
bwoebi (bwoebi)  
colinodell (colinodell)  
crell (crell)  
dharman (dharman)  
galvao (galvao)  
girgias (girgias)  
imsop (imsop)  
kalle (kalle)  
kocsismate (kocsismate)  
levim (levim)  
mauricio (mauricio)  
nicolasgrekas (nicolasgrekas)  
ocramius (ocramius)  
petk (petk)  
ramsey (ramsey)  
sebastian (sebastian)  
sergey (sergey)  
svpernova09 (svpernova09)  
theodorejb (theodorejb)  
timwolla (timwolla)  
trowski (trowski)  
Final result: 24 0
This poll has been closed.

Implementation

Implemented in PHP 8.3:

  1. a link to the PHP manual entry for the feature
rfc/assert-string-eval-cleanup.txt · Last modified: 2023/07/13 14:46 by girgias