rfc:allow_null

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
rfc:allow_null [2022/02/08 14:43] – Add example changes craigfrancisrfc:allow_null [2022/04/05 17:49] (current) – superseded craigfrancis
Line 1: Line 1:
 ====== PHP RFC: Allow NULL ====== ====== PHP RFC: Allow NULL ======
  
-  * Version: 1.1+  * Version: 1.3
   * Voting Start: ?   * Voting Start: ?
   * Voting End: ?   * Voting End: ?
   * RFC Started: 2021-12-23   * RFC Started: 2021-12-23
-  * RFC Updated: 2021-12-31+  * RFC Updated: 2022-02-20
   * Author: Craig Francis, craig#at#craigfrancis.co.uk   * Author: Craig Francis, craig#at#craigfrancis.co.uk
   * Status: Draft   * Status: Draft
Line 11: Line 11:
   * GitHub Repo: https://github.com/craigfrancis/php-allow-null-rfc   * GitHub Repo: https://github.com/craigfrancis/php-allow-null-rfc
   * Implementation: ?   * Implementation: ?
 +
 +----
 +
 +This RFC has been superseded by [[https://wiki.php.net/rfc/null_coercion_consistency|NULL Coercion Consistency]]
 +
 +----
  
 ===== Introduction ===== ===== Introduction =====
Line 16: Line 22:
 PHP 8.1 introduced "Deprecate passing null to non-nullable arguments of internal functions" ([[https://externals.io/message/112327|short discussion]]), which is making it difficult (time consuming) for developers to upgrade. PHP 8.1 introduced "Deprecate passing null to non-nullable arguments of internal functions" ([[https://externals.io/message/112327|short discussion]]), which is making it difficult (time consuming) for developers to upgrade.
  
-Often //NULL// is used for undefined //GET/////POST/////COOKIE// variables:+This has introduced an inconstancy when not using //strict_types=1//, because most variables types (e.g. integers) can be coerced to the relevant type, but //NULL// has been deprecated. 
 + 
 +In PHP //NULL// is often used to represent something; e.g. when a //GET/////POST/////COOKIE// variable is undefined:
  
 <code php> <code php>
Line 35: Line 43:
   * //json_decode()//   * //json_decode()//
  
-Which makes it common for //NULL// to be passed to internal functions, e.g.+This makes it common for //NULL// to be passed to many internal functions, e.g.
  
 <code php> <code php>
Line 50: Line 58:
 </code> </code>
  
-Another example is when PHP provides //NULL// for undefined variables, e.g.+Developers also use //NULL// to skip certain parameters, e.g. //$additional_headers// in //mail()//.
  
-<code php> +Where //NULL// has always been coerced into an empty string, the integer 0, the boolean false, etc.
-locale_accept_from_http($_SERVER['HTTP_ACCEPT_LANGUAGE']); +
-</code>+
  
-Or when developers explicitly use //NULL// to skip certain parameters, e.g. //$additional_headers// in //mail()//.+Currently the deprecation notices only affect those using PHP 8.1 with //E_DEPRECATED//, but it implies everyone will need to modify their code to avoid **Fatal Errors** in PHP 9.0.
  
-Currently this only affects those using PHP 8.1 with //E_DEPRECATED//, but it implies everyone will need to modify their code in the future - presumably this will be a **fatal error** in PHP 9.0, with a //TypeError// exception?+Developers using //strict_types=1// may find some value in this, but it's excessive and inconstant for everyone else.
  
-This also applies to those developers not using //strict_types=1//, which is excessive. +And while individual changes are easy, there are many of them (time consuming), difficult to find, and often pointless, e.g.
- +
-While individual changes are easy, there are many of them, difficult to find, and often pointless, e.g.+
  
   * urlencode(strval($name));   * urlencode(strval($name));
Line 68: Line 72:
   * urlencode($name ?? '');   * urlencode($name ?? '');
  
-Without the changes below, developers will need to either - use these deprecation notices, or use very strict Static Analysis (one that can determine when a variable can be //NULL//; e.g. Psalm at [[https://psalm.dev/docs/running_psalm/error_levels/|level 3]], with no baseline).+To find these issues, developers need to either - use these deprecation notices, or use very strict Static Analysis (one that can determine when a variable can be //NULL//; e.g. Psalm at [[https://psalm.dev/docs/running_psalm/error_levels/|level 3]], with no baseline).
  
-===== Proposal =====+It's worth noting that some parameters, like //$separator// in //explode()//, already have a "cannot be empty" Fatal Error. So it might be useful to have a separate RFC to update some of these parameters to consistently reject NULL **or** Empty Strings, e.g. //$needle// in //strpos()// and //$json// in //json_decode()//.
  
-Update **some** internal function parameters to accept (be tolerant to) //NULL//.+===== Proposal =====
  
-This needs to be done before the eventual end of the deprecation period, and //TypeError// exceptions are thrown, which would create an unnecessary burden for developers to upgrade.+There are 3 possible approaches:
  
-While this is in Draftthe [[https://github.com/craigfrancis/php-allow-null-rfc/blob/main/functions-change.md|list of functions are hosted on GitHub]].+  - NULL triggers a Fatal Error with strict_types=1otherwise allow coercion (like how integers can be coerced to a string). 
 +  NULL triggers a Fatal Error for everyone, but update some parameters to explicitly allow NULL (e.g. //?string//). 
 +  - NULL triggers a Fatal Error for everyone (forget about backwards compatibility).
  
-Only the parameters in **bold** would be changed.+This needs to be done before the eventual end of the deprecation period, and //TypeError// exceptions are thrown.
  
-Suggestions and pull requests welcome.+If we choose to "update some parameters to explicitly allow NULL", there is a [[https://github.com/craigfrancis/php-allow-null-rfc/blob/main/functions-change.md|draft list of functions]], where the **bold** are being proposed (currently only includes string parameters). [[https://github.com/craigfrancis/php-allow-null-rfc/issues|Suggestions]] and [[https://github.com/craigfrancis/php-allow-null-rfc/pulls|Pull Requests]] welcome.
  
-There is also a [[https://github.com/craigfrancis/php-allow-null-rfc/blob/main/functions-maybe.md|Maybe List]], where the more questionable arguments end with a "!". For example, //strrpos()// accepting an empty string for //$needle// is wired in itself, and //sodium_crypto_box_open()// should never receive a blank //$ciphertext//.+There is also a [[https://github.com/craigfrancis/php-allow-null-rfc/blob/main/functions-maybe.md|Maybe List]], where the more questionable arguments end with a "!". For example, //strrpos()// accepting an empty string for //$needle// is wired in itself, and //sodium_crypto_box_open()// should never receive a blank //$ciphertext//. And there is an [[https://github.com/craigfrancis/php-allow-null-rfc/blob/main/functions-other.md|Other List]], which can be ignored.
  
 ===== Decision Process ===== ===== Decision Process =====
  
-Does the parameter work with //NULL//, in the same way it would with an empty string? e.g.+Does //NULL// for this parameter justify a Fatal Error? e.g.
  
   - //preg_match()// should **deprecate** //NULL// for //$pattern// ("empty regular expression" warning).   - //preg_match()// should **deprecate** //NULL// for //$pattern// ("empty regular expression" warning).
Line 123: Line 129:
 ===== Future Scope ===== ===== Future Scope =====
  
-Some functions parameters could be updated to complain when an Empty String or //NULL// is provided.+Some function parameters could be updated to complain when an //NULL// **or** //Empty String// is provided; e.g. //$method// in //method_exists()//, or //$characters// in //trim()//.
  
 ===== Voting ===== ===== Voting =====
Line 131: Line 137:
 TODO TODO
  
-===== Patches and Tests =====+===== Tests =====
  
 To get and **Test** the list of functions, I wrote a script to //get_defined_functions()//, then used //ReflectionFunction()// to identify parameters that accepted the 'string' type, and not //->allowsNull()//. This resulted in the [[https://github.com/craigfrancis/php-allow-null-rfc/blob/main/functions-change.md|list of functions to change]], where I manually removed the [[https://github.com/craigfrancis/php-allow-null-rfc/blob/main/functions-other.md|functions that shouldn't be changed]], and updated the script to test every argument (to see that it complained with //NULL//, and the output remained the same) - [[https://github.com/craigfrancis/php-allow-null-rfc/blob/main/functions.php|Source]]. To get and **Test** the list of functions, I wrote a script to //get_defined_functions()//, then used //ReflectionFunction()// to identify parameters that accepted the 'string' type, and not //->allowsNull()//. This resulted in the [[https://github.com/craigfrancis/php-allow-null-rfc/blob/main/functions-change.md|list of functions to change]], where I manually removed the [[https://github.com/craigfrancis/php-allow-null-rfc/blob/main/functions-other.md|functions that shouldn't be changed]], and updated the script to test every argument (to see that it complained with //NULL//, and the output remained the same) - [[https://github.com/craigfrancis/php-allow-null-rfc/blob/main/functions.php|Source]].
Line 139: Line 145:
 https://github.com/craigfrancis/php-src/compare/master...allow-null https://github.com/craigfrancis/php-src/compare/master...allow-null
  
-This patch currently defines //Z_PARAM_STR_ALLOW_NULL//.+This patch defines //Z_PARAM_STR_ALLOW_NULL//.
  
 It works a bit like //Z_PARAM_STR_OR_NULL//, but it will return an empty string instead of //NULL//. It works a bit like //Z_PARAM_STR_OR_NULL//, but it will return an empty string instead of //NULL//.
  
-It's a fairly easy drop in replacement for //Z_PARAM_STR//, which is used by functions like [[https://github.com/php/php-src/blob/7b90ebeb3f954123915f6d62fb7b2cd3fdf3c6ec/ext/standard/html.c#L1324|htmlspecialchars()]].+It's a fairly easy drop in replacement for //Z_PARAM_STR//, e.g. [[https://github.com/php/php-src/blob/7b90ebeb3f954123915f6d62fb7b2cd3fdf3c6ec/ext/standard/html.c#L1324|htmlspecialchars()]].
  
 ===== Rejected Features ===== ===== Rejected Features =====
rfc/allow_null.1644331426.txt.gz · Last modified: 2022/02/08 14:43 by craigfrancis