rfc:isset_ternary

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
Last revisionBoth sides next revision
rfc:isset_ternary [2014/09/09 01:15] – ` to '' ajfrfc:isset_ternary [2016/03/13 02:04] – Add Errata section ajf
Line 1: Line 1:
-====== PHP RFC: Implicit isset() in Shorthand Ternary Operator ====== +====== PHP RFC: Null Coalesce Operator ====== 
-  * Version: 0.1 +  * Version: 0.2.3 
-  * Date: 2014-09-06 +  * Date: 2014-09-06, last updated 2014-09-16 
-  * Author: Andrea Fauldsajf@ajf.me +  * Author: Andrea Faulds <ajf@ajf.me
-  * Status: Under Discussion+  * Contributor: Nikita Popov <nikic@php.net> (initial patch) 
 +  * Status: Implemented (PHP 7)
   * First Published at: http://wiki.php.net/rfc/isset_ternary   * First Published at: http://wiki.php.net/rfc/isset_ternary
  
Line 9: Line 10:
 ===== Introduction ===== ===== Introduction =====
  
-PHP is a web-focussed programming language, so processing user data is a frequent activity. In such processing it is common to check for something's existence, and if it doesn't exist, use a default value. Yet the simplest way to do this, something along the lines of ''isset($_GET['mykey']) ? $_GET['mykey'] : ""'', is unnecessarily cumbersome. The short ternary operator, ''?:'' provides a way to do this much more conveniently: ''$_GET['mykey'] ? ""''. However, this is not good practise, as if the value does not exist it will raise an ''E_NOTICE''. Because of these issues, some sort of ifsetor() operator or a modification to ''?:'''s behaviour to make this common pattern easier has been a frequent request (See References).+PHP is a web-focussed programming language, so processing user data is a frequent activity. In such processing it is common to check for something's existence, and if it doesn't exist, use a default value. Yet the simplest way to do this, something along the lines of ''<nowiki>isset($_GET['mykey']) ? $_GET['mykey'] : ""</nowiki>'', is unnecessarily cumbersome. The short ternary operator, ''?:'' provides a way to do this much more conveniently: ''<nowiki>$_GET['mykey'] ?""</nowiki>''. However, this is not good practice, as if the value does not exist it will raise an ''E_NOTICE''. Because of these issues, some sort of ifsetor() operator or a modification to ''?:'''s behaviour to make this common pattern easier has been a frequent request (See References).
  
 ===== Proposal ===== ===== Proposal =====
  
-The ''?:'' operator is overloadedsuch that if the first operand can be used with ''isset''an implicit ''isset'' is performed alongside the truthiness check. This means the ''$_GET['mykey'] ?""'' shorthand is completely safe and will not raise an E_NOTICE.+The coalesce, or ''??''operator is addedwhich returns the result of its first operand if it exists and is not NULLor else its second operand. This means the ''<nowiki>$_GET['mykey'] ?""</nowiki>'' is completely safe and will not raise an E_NOTICE. Some examples of its use:
  
-Internally this is actually implemented by rewriting the expression within the compiler from ''$a ?: $b'' to ''empty($a) ? $b : $a'' if ''$a'' would work with ''isset''. This avoids introducing any new opcodes and allows us to leverage the existing infrastructure in place for ''empty''.+<code php> 
 +// Fetches the request parameter user and results in 'nobodyif it doesn't exist 
 +$username = $_GET['user'] ?? 'nobody'
 +// equivalent to: $username = isset($_GET['user']) ? $_GET['user'] : 'nobody';
  
-==== Backwards-compatibility considerations ====+// Calls a hypothetical model-getting function, and uses the provided default if it fails 
 +$model Model::get($id) ?? $default_model; 
 +// equivalent to: if (($model Model::get($id)) === NULL) { $model $default_model; }
  
-Because ''empty'' is used, which performs a falsiness check, existing code using the ''?:'' operator should function the same. However, now no ''E_NOTICE'' will be raised if the variable does not exist. While this should not affect most applications, it might affect some applications using custom error handlers, so this is a minor backwards-compatibility break and targets a major version.+// Parse JSON image metadata, and if the width is missing, assume 100 
 +$imageData = json_decode(file_get_contents('php://input')); 
 +$width = $imageData['width'] ?100; 
 +// equivalent to$width = isset($imageData['width']) ? $imageData['width'] : 100; 
 +</code>
  
-===== Proposed PHP Version(s) =====+It can even be chained:
  
-This proposed for the next PHP x, which at the time of this writing would be PHP 7.+<code php> 
 +$= NULL; 
 +$y = NULL; 
 +$z = 3; 
 +var_dump($x ?? $y ?? $z); // int(3)
  
-===== Open Issues =====+$x ["yarr" => "meaningful_value"]; 
 +var_dump($x["aharr"] ?? $x["waharr"] ?? $x["yarr"]); // string(16) "meaningful_value" 
 +</code>
  
-None I'm aware of.+This example demonstrates the precedence relative to the ternary operator and the boolean or operator, which is the same as C#:
  
-===== Unaffected PHP Functionality =====+<code php> 
 +var_dump(2 ?? 3 ? 4 : 5);      // (2 ?? 3) ? 4 : 5        => int(4) 
 +var_dump(0 || 2 ?? 3 ? 4 : 5); // ((0 || 2) ?? 3) ? 4 : 5 => int(4) 
 +</code>
  
-The behaviour of the long-form ternary operator, ''$a ? $b $c'', ''isset'' and ''empty'' are unaffected. Where the expression is not compatible with ''isset'', the existing behaviour continues to be used.+This example demonstrates how it is a short-circuiting operator:
  
-===== Future Scope =====+<code php> 
 +function foo() { 
 +    echo "executed!", PHP_EOL; 
 +
 +var_dump(true ?? foo()); // outputs bool(true), "executed!" does not appear as it short-circuited 
 +</code>
  
-None I can think of currently.+===== Proposed PHP Version(s) =====
  
-===== Proposed Voting Choices ===== +This proposed for the next PHP xwhich at the time of this writing would be PHP 7.
- +
-As this is a language changea 2/3 majority is required. A straight Yes/No vote would be held.+
  
 ===== Patches and Tests ===== ===== Patches and Tests =====
  
-A pull request with a working implementation and test, targeting master, is here: https://github.com/php/php-src/pull/809+A pull request with a working implementation and test, targeting master, is here: https://github.com/php/php-src/pull/824 
 + 
 +The original patch was graciously provided by Nikita Popov. 
 + 
 +===== Vote ===== 
 + 
 +As this is a language change, a 2/3 majority is required. A straight Yes/No vote is being held. 
 + 
 +Voting started on 2014-09-20 and ended on 2014-09-27. 
 + 
 +<doodle title="Approve Null Coalesce Operator RFC and merge patch into master?" auth="ajf" voteType="single" closed="true"> 
 +   * Yes 
 +   * No 
 +</doodle>
  
 ===== Implementation ===== ===== Implementation =====
-After the project is implemented, this section should contain  + 
-  - the version(sit was merged to +Merged into master (which will be PHP 7): https://github.com/php/php-src/commit/2d069f640e6cccfa3ba8b1e4f375ade20fb33f64 
-  a link to the git commit(s) + 
-  - a link to the PHP manual entry for the feature+Documented at: http://php.net/manual/en/language.operators.comparison.php
  
 ===== References ===== ===== References =====
Line 65: Line 100:
  
 This list is quite probably incomplete. This list is quite probably incomplete.
 +
 +Operator precedence in C#: http://msdn.microsoft.com/en-us/library/6a71f45d.aspx
  
 ===== Rejected Features ===== ===== Rejected Features =====
 Keep this updated with features that were discussed on the mail lists. Keep this updated with features that were discussed on the mail lists.
 +
 +===== Errata =====
 +
 +The name of this RFC [[http://blog.ajf.me/2015-12-07-poorly-named-rfcs|ought to have been "null coalescing operator", not "null coalesce operator"]].
 +
 +===== Changelog =====
 +
 +  * (2016-03-13) Added Errata
 +  * v0.2.3 - Added short-circuit example
 +  * v0.2.2 - Added precedence example
 +  * v0.2.1 - Added chaining example
 +  * v0.2 - Overhauled proposal, proposing new operator ''??'' instead of an extension to ''?:''
 +  * v0.1 - Created
rfc/isset_ternary.txt · Last modified: 2017/09/22 13:28 by 127.0.0.1