rfc:new_without_parentheses

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:new_without_parentheses [2024/04/08 06:01] – Fixed creation date vudaltsovrfc:new_without_parentheses [2024/05/28 18:04] (current) – Added Target Version vudaltsov
Line 2: Line 2:
  
   * Date: 2023-12-29   * Date: 2023-12-29
-  * Author: Valentin Udaltsov <vudaltsov@php.net> +  * Author: Valentin Udaltsov (udaltsov.valentin@gmail.com) 
-  * Status: Under Discussion+  * Status: Implemented 
 +  * Target Version: PHP 8.4 
 +  * Discussion: https://externals.io/message/123031
   * First Published at: http://wiki.php.net/rfc/new_without_parentheses   * First Published at: http://wiki.php.net/rfc/new_without_parentheses
   * Implementation: https://github.com/php/php-src/pull/13029   * Implementation: https://github.com/php/php-src/pull/13029
Line 15: Line 17:
  
 <code php> <code php>
-class MyClass+class Request implements Psr\Http\Message\RequestInterface
 { {
-    public function method(): void +    // ...
-    { +
-        echo 'Hello, World!'; +
-    }+
 } }
  
-(new MyClass())->method()// Hello, World!+// OK 
 +$request = (new Request())->withMethod('GET')->withUri('/hello-world');
  
-new MyClass()->method(); // PHP Parse error: syntax error, unexpected token "->"+// PHP Parse error: syntax error, unexpected token "->" 
 +$request = new Request()->withMethod('GET')->withUri('/hello-world');
 </code> </code>
  
 The goal of this RFC is to enable the second syntax to: The goal of this RFC is to enable the second syntax to:
   * make coding with PHP more convenient and satisfy many users' requests for this feature (see [[https://externals.io/message/66197|externals#66197]], [[https://bugs.php.net/bug.php?id=70549|bugs.php#70549]], [[https://externals.io/message/101811|externals#101811]], [[https://externals.io/message/113953|externals#113953]])   * make coding with PHP more convenient and satisfy many users' requests for this feature (see [[https://externals.io/message/66197|externals#66197]], [[https://bugs.php.net/bug.php?id=70549|bugs.php#70549]], [[https://externals.io/message/101811|externals#101811]], [[https://externals.io/message/113953|externals#113953]])
-  * decrease the visual debt ([[https://github.com/search?q=path%3A*.php+language%3APHP+%2F%5C%28%5Cs*new%5Cs%2B%5B%5E%5C%28%5D%2B%5Cs*%5C%28%5B%5E%5C%29%5D*%5C%29%5Cs*%5C%29%5Cs*-%3E%2F&type=code&ref=advsearch|more than half a million lines of open source PHP code could be simplified]])+  * decrease the visual debt in all sorts of builders and configurators ([[https://github.com/search?q=path%3A*.php+language%3APHP+%2F%5C%28%5Cs*new%5Cs%2B%5B%5E%5C%28%5D%2B%5Cs*%5C%28%5B%5E%5C%29%5D*%5C%29%5Cs*%5C%29%5Cs*-%3E%2F&type=code&ref=advsearch|more than half a million lines of open source PHP code could be simplified]])
   * ease switching between other C-like languages that don't require parentheses ([[https://onecompiler.com/java/3zxuee3bm|Java]], [[https://onecompiler.com/csharp/3zxudhw4s|C#]], [[https://onecompiler.com/typescript/3zxudfpyy|TypeScript]]).   * ease switching between other C-like languages that don't require parentheses ([[https://onecompiler.com/java/3zxuee3bm|Java]], [[https://onecompiler.com/csharp/3zxudhw4s|C#]], [[https://onecompiler.com/typescript/3zxudfpyy|TypeScript]]).
  
 ===== Proposal ===== ===== Proposal =====
  
-This RFC allows to omit parentheses around the ''new'' expression when constructor arguments' parentheses **are** present. Given class+This RFC allows to omit parentheses around the ''new'' expression **with** constructor arguments' parentheses. Given class
  
 <code php> <code php>
-class MyClass+class MyClass extends ArrayObject
 { {
     const CONSTANT = 'constant';     const CONSTANT = 'constant';
Line 59: Line 60:
     new MyClass()->method(),        // string(6)  "method"     new MyClass()->method(),        // string(6)  "method"
     new MyClass()(),                // string(8)  "__invoke"     new MyClass()(),                // string(8)  "__invoke"
 +    new MyClass(['value'])[0],      // string(5)  "value"
 ); );
  
Line 69: Line 71:
     new $myClass()->method(),        // string(6)  "method"     new $myClass()->method(),        // string(6)  "method"
     new $myClass()(),                // string(8)  "__invoke"     new $myClass()(),                // string(8)  "__invoke"
 +    new $myClass(['value'])[0],      // string(5)  "value"
 ); );
  
Line 78: Line 81:
     new (trim(' MyClass '))()->method(),        // string(6)  "method"     new (trim(' MyClass '))()->method(),        // string(6)  "method"
     new (trim(' MyClass '))()(),                // string(8)  "__invoke"     new (trim(' MyClass '))()(),                // string(8)  "__invoke"
 +    new (trim(' MyClass '))(['value'])[0],      // string(5)  "value"
 ); );
 </code> </code>
  
-This RFC still does not allow to omit parentheses around the ''new'' expression **without** constructor arguments' parentheses, because in some cases +This RFC does not change behavior of ''new'' expressions **without** constructor arguments' parentheses:
-this leads to an ambiguity:+
  
 <code php> <code php>
-// Instantiate and then access the instance or instantiate the result of the expression? +new MyClass::CONSTANT; // will continue to throw a syntax error 
-new MyClass::CONSTANT; +new $myClass::CONSTANT; // will continue to throw a syntax error 
-new MyClass::$staticProperty; +new MyClass::$staticProperty; // will continue to work as `new (MyClass::$staticProperty)` 
-new $myClass::CONSTANT; +new $myClass::$staticProperty// will continue to work as `new ($myClass::$staticProperty)` 
-new $myClass::$staticProperty; +new $myObject->property; // will continue to work as `new ($myObject->property)
-new $myClass->property; +new MyArrayConst['class']// will continue to throw a syntax error 
-new $myClass->method();+new $myArray['class']; // will continue to work as `new ($myArray['class'])`
 </code> </code>
  
Line 111: Line 114:
     // string(8) "__invoke"     // string(8) "__invoke"
     new class { public function __invoke() { return '__invoke'; } }(),     new class { public function __invoke() { return '__invoke'; } }(),
 +    // string(5) "value"
 +    new class (['value']) extends ArrayObject {}[0],
 ); );
 </code> </code>
Line 157: Line 162:
 without any additional parentheses. It also becomes clear why ''new_variable'' cannot have calls and why arguments' parentheses without any additional parentheses. It also becomes clear why ''new_variable'' cannot have calls and why arguments' parentheses
 are crucial for the proposed syntax: parentheses denote the end of the class name and the end of the new expression. are crucial for the proposed syntax: parentheses denote the end of the class name and the end of the new expression.
 +
 +===== Other syntax ideas =====
 +
 +Some of the ideas expressed during the discussion of this RFC are listed below. They are orthogonal to this proposal and
 +require a separate RFC.
 +
 +==== Allow to omit the new keyword ====
 +
 +Some languages like Kotlin allow to instantiate classes via [[https://onecompiler.com/kotlin/42b54ds4u|MyClass() expression]].
 +Omitting the "new" keyword in PHP is currently not possible, because classes and functions can [[https://3v4l.org/mfUVp|have the same name]]
 +(in Kotlin [[https://onecompiler.com/kotlin/42b579yhu|it is not possible]]). So, in order to achieve this in PHP, we should first
 +deprecate declaring functions and classes with the same names.
 +
 +==== MyClass::new(), MyClass::create() ====
 +
 +Introducing a dedicated static constructor like ''MyClass::new()'' or ''MyClass::create()'' would be a backward compatibility
 +break for already existing static or object methods named ''new'' or ''create'' with required parameters and/or return
 +type different from ''static''. So this idea also requires some deprecations.
  
 ===== Backward Incompatible Changes ===== ===== Backward Incompatible Changes =====
Line 165: Line 188:
  
 PHP 8.4 PHP 8.4
 +
 +===== Proposed Voting Choices =====
 +
 +This is a simple yes-or-no vote to include this feature. 2/3 majority required to pass. 
 +
 +Voting started on 2024-05-09 and will end on 2024-05-24 00:00 GMT.
 +
 +<doodle title="Allow to omit parentheses around the new expression as described?" auth="vudaltsov" voteType="single" closed="true" closeon="2024-05-24T00:00:00Z">
 +   * Yes
 +   * No
 +</doodle>
 +
 +===== Implementation =====
 +
 +Pull request contains the final implementation and plenty of tests asserting the expected behavior and backward compatibility: https://github.com/php/php-src/pull/13029
 +
 +===== References =====
 +
 +  * [[https://externals.io/message/123031|This RFC discussion thread]]
 +
 +Old requests for this feature:
 +
 +  * [[https://externals.io/message/66197|Allow (...)->foo() expressions not only for `new` (see end of the page)]]
 +  * [[https://bugs.php.net/bug.php?id=70549|Allow `new Foo()->bar()` without parens around `(new Foo)`]]
 +  * [[https://externals.io/message/101811|Suggested change: change priority of new and ->]]
 +  * [[https://externals.io/message/113953|Raising the precedence of the new operator]]
 +
  
rfc/new_without_parentheses.1712556064.txt.gz · Last modified: 2024/04/08 06:01 by vudaltsov