]> granicus.if.org Git - php/commitdiff
- Added class member access on instantiation (e.g. (new foo)->bar()) support
authorFelipe Pena <felipe@php.net>
Sun, 6 Nov 2011 13:25:45 +0000 (13:25 +0000)
committerFelipe Pena <felipe@php.net>
Sun, 6 Nov 2011 13:25:45 +0000 (13:25 +0000)
NEWS
UPGRADING
Zend/tests/indirect_method_call_001.phpt [new file with mode: 0644]
Zend/tests/indirect_method_call_002.phpt [new file with mode: 0644]
Zend/tests/indirect_method_call_003.phpt [new file with mode: 0644]
Zend/tests/indirect_method_call_004.phpt [new file with mode: 0644]
Zend/tests/indirect_method_call_005.phpt [new file with mode: 0644]
Zend/tests/indirect_property_access.phpt [new file with mode: 0644]
Zend/zend_language_parser.y

diff --git a/NEWS b/NEWS
index 0130d1620ead6d0997cd1c6c3810ebf9372e4b4a..c41202e356376ecae4acb44c9c155f7e8ac1b01b 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,8 @@ PHP                                                                        NEWS
 ?? ??? 2011, PHP 5.4.0 RC1
 - General improvements:
   . Changed silent conversion of array to string to produce a notice. (Patrick)
+  . Added class member access on instantiation (e.g. (new foo)->bar()) support.
+    (Felipe)
 
 - CLI SAPI:
   . Fixed bug #60112 (If URI does not contain a file, index.php is not served).
index d8ed3190c8e079751d7f853e96d071eddb0af768..58a318323cbbf62a9e13e9cfa53818c31e9fed38 100755 (executable)
--- a/UPGRADING
+++ b/UPGRADING
@@ -461,6 +461,10 @@ UPGRADE NOTES - PHP 5.4
     $y = "o"; 
     A::{$x.$y.$y}();
 
+- Class member acces on instantiation:
+  (new foo)->method()
+  (new foo)->property
+  (new foo)[0]
 
 ===================
 13. Windows support
diff --git a/Zend/tests/indirect_method_call_001.phpt b/Zend/tests/indirect_method_call_001.phpt
new file mode 100644 (file)
index 0000000..7018eaa
--- /dev/null
@@ -0,0 +1,20 @@
+--TEST--
+Testing indirect method call and exceptions
+--FILE--
+<?php
+
+class foo {
+       public function __construct() {
+               throw new Exception('foobar');
+       }
+}
+
+try {
+       $X = (new foo)->Inexistent(3);
+} catch (Exception $e) {
+       var_dump($e->getMessage()); // foobar
+}
+
+?>
+--EXPECT--
+string(6) "foobar"
diff --git a/Zend/tests/indirect_method_call_002.phpt b/Zend/tests/indirect_method_call_002.phpt
new file mode 100644 (file)
index 0000000..1589533
--- /dev/null
@@ -0,0 +1,32 @@
+--TEST--
+Indirect method call with chaining
+--FILE--
+<?php
+
+class foo {
+       public $x = 'testing';
+
+       public function bar() {
+               return "foo";
+       }
+       public function baz() {
+               return new self;
+       }
+       static function xyz() {
+       }
+}
+
+var_dump((new foo())->bar());               // string(3) "foo"
+var_dump((new foo())->baz()->x);            // string(7) "testing"
+var_dump((new foo())->baz()->baz()->bar()); // string(3) "foo"
+var_dump((new foo())->xyz());               // NULL
+(new foo())->www();
+
+?>
+--EXPECTF--
+string(3) "foo"
+string(7) "testing"
+string(3) "foo"
+NULL
+
+Fatal error: Call to undefined method foo::www() in %s on line %d
diff --git a/Zend/tests/indirect_method_call_003.phpt b/Zend/tests/indirect_method_call_003.phpt
new file mode 100644 (file)
index 0000000..3df4954
--- /dev/null
@@ -0,0 +1,23 @@
+--TEST--
+Testing indirect method call
+--FILE--
+<?php
+
+class foo {
+       public $x = 1;
+
+       public function getX() {
+               return $this->x;
+       }
+       public function setX($val) {
+               $this->x = $val;
+               return $this;
+       }
+}
+
+$X = (new foo)->setX(10)->getX();
+var_dump($X); // int(10)
+
+?>
+--EXPECT--
+int(10)
diff --git a/Zend/tests/indirect_method_call_004.phpt b/Zend/tests/indirect_method_call_004.phpt
new file mode 100644 (file)
index 0000000..689600d
--- /dev/null
@@ -0,0 +1,26 @@
+--TEST--
+Indirect method call and cloning
+--FILE--
+<?php
+
+
+class bar {
+       public $z;
+
+       public function __construct() {
+               $this->z = new stdclass;
+       }
+       public function getZ() {
+               return $this->z;
+       }
+}
+
+var_dump(clone (new bar)->z);
+var_dump(clone (new bar)->getZ());
+
+?>
+--EXPECTF--
+object(stdClass)#%d (0) {
+}
+object(stdClass)#%d (0) {
+}
diff --git a/Zend/tests/indirect_method_call_005.phpt b/Zend/tests/indirect_method_call_005.phpt
new file mode 100644 (file)
index 0000000..4f4b363
--- /dev/null
@@ -0,0 +1,16 @@
+--TEST--
+Testing array dereferencing from instance with ArrayObject
+--FILE--
+<?php
+
+class foo extends ArrayObject {
+       public function __construct($arr) {
+               parent::__construct($arr);
+       }
+}
+
+var_dump( (new foo( array(1, array(4, 5), 3) ))[1][0] ); // int(4)
+
+?>
+--EXPECT--
+int(4)
diff --git a/Zend/tests/indirect_property_access.phpt b/Zend/tests/indirect_property_access.phpt
new file mode 100644 (file)
index 0000000..3645687
--- /dev/null
@@ -0,0 +1,26 @@
+--TEST--
+Testing indirect property access
+--FILE--
+<?php
+
+class foo {
+       public $x = 1;
+}
+
+class bar {
+       public $y = 'foo';
+}
+
+$x = 'bar';
+
+$bar = new bar;
+
+var_dump((new bar)->y);     // foo
+var_dump((new $x)->y);      // foo
+var_dump((new $bar->y)->x); // 1
+
+?>
+--EXPECT--
+string(3) "foo"
+string(3) "foo"
+int(1)
index 906242fb48212157e6079309e99c37f89cf10f47..a0c671b34cea931258d5a22919cf67b8acac0e4c 100644 (file)
@@ -50,7 +50,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
 %}
 
 %pure_parser
-%expect 2
+%expect 3
 
 %token END 0 "end of file"
 %left T_INCLUDE T_INCLUDE_ONCE T_EVAL T_REQUIRE T_REQUIRE_ONCE
@@ -694,12 +694,37 @@ non_empty_for_expr:
        |       expr                                    { $$ = $1; }
 ;
 
+chaining_method_or_property:
+               chaining_method_or_property variable_property   { $$.EA = $2.EA; }
+       |       variable_property                                                               { $$.EA = $1.EA; }
+;
+
+chaining_dereference:
+               chaining_dereference '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); }
+       |       '[' dim_offset ']'              { zend_do_pop_object(&$1 TSRMLS_CC); fetch_array_dim(&$$, &$1, &$2 TSRMLS_CC); }
+;
+
+chaining_instance_call:
+               chaining_dereference            { zend_do_push_object(&$1 TSRMLS_CC); } chaining_method_or_property { $$ = $3; }
+       |       chaining_dereference            { zend_do_push_object(&$1 TSRMLS_CC); $$ = $1; }
+       |       chaining_method_or_property { $$ = $1; }
+;
+
+instance_call:
+               /* empty */             { $$ = $0; }
+       |       { zend_do_push_object(&$0 TSRMLS_CC); zend_do_begin_variable_parse(TSRMLS_C); }
+               chaining_instance_call  { zend_do_pop_object(&$$ TSRMLS_CC); zend_do_end_variable_parse(&$2, BP_VAR_R, 0 TSRMLS_CC); }
+;
+
+new_expr:
+               T_NEW class_name_reference { zend_do_extended_fcall_begin(TSRMLS_C); zend_do_begin_new_object(&$1, &$2 TSRMLS_CC); } ctor_arguments { zend_do_end_new_object(&$$, &$1, &$4 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);}
+;
+
 expr_without_variable:
                T_LIST '(' { zend_do_list_init(TSRMLS_C); } assignment_list ')' '=' expr { zend_do_list_end(&$$, &$7 TSRMLS_CC); }
        |       variable '=' expr               { zend_check_writable_variable(&$1); zend_do_assign(&$$, &$1, &$3 TSRMLS_CC); }
        |       variable '=' '&' variable { zend_check_writable_variable(&$1); zend_do_end_variable_parse(&$4, BP_VAR_W, 1 TSRMLS_CC); zend_do_end_variable_parse(&$1, BP_VAR_W, 0 TSRMLS_CC); zend_do_assign_ref(&$$, &$1, &$4 TSRMLS_CC); }
        |       variable '=' '&' T_NEW class_name_reference { zend_error(E_DEPRECATED, "Assigning the return value of new by reference is deprecated");  zend_check_writable_variable(&$1); zend_do_extended_fcall_begin(TSRMLS_C); zend_do_begin_new_object(&$4, &$5 TSRMLS_CC); } ctor_arguments { zend_do_end_new_object(&$3, &$4, &$7 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); zend_do_end_variable_parse(&$1, BP_VAR_W, 0 TSRMLS_CC); $3.EA = ZEND_PARSED_NEW; zend_do_assign_ref(&$$, &$1, &$3 TSRMLS_CC); }
-       |       T_NEW class_name_reference { zend_do_extended_fcall_begin(TSRMLS_C); zend_do_begin_new_object(&$1, &$2 TSRMLS_CC); } ctor_arguments { zend_do_end_new_object(&$$, &$1, &$4 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);}
        |       T_CLONE expr { zend_do_clone(&$$, &$2 TSRMLS_CC); }
        |       variable T_PLUS_EQUAL expr      { zend_check_writable_variable(&$1); zend_do_end_variable_parse(&$1, BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_ADD, &$$, &$1, &$3 TSRMLS_CC); }
        |       variable T_MINUS_EQUAL expr     { zend_check_writable_variable(&$1); zend_do_end_variable_parse(&$1, BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_SUB, &$$, &$1, &$3 TSRMLS_CC); }
@@ -746,6 +771,8 @@ expr_without_variable:
        |       expr T_IS_GREATER_OR_EQUAL expr { zend_do_binary_op(ZEND_IS_SMALLER_OR_EQUAL, &$$, &$3, &$1 TSRMLS_CC); }
        |       expr T_INSTANCEOF class_name_reference { zend_do_instanceof(&$$, &$1, &$3, 0 TSRMLS_CC); }
        |       '(' expr ')'    { $$ = $2; }
+       |       new_expr                { $$ = $1; }
+       |       '(' new_expr ')' { $$ = $2; } instance_call { $$ = $5; }
        |       expr '?' { zend_do_begin_qm_op(&$1, &$2 TSRMLS_CC); }
                expr ':' { zend_do_qm_true(&$4, &$2, &$5 TSRMLS_CC); }
                expr     { zend_do_qm_false(&$$, &$7, &$2, &$5 TSRMLS_CC); }