Skip to content

Implement the RFC Catchable "Call to a member function bar()..." #847

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed

Conversation

thekid
Copy link
Contributor

@thekid thekid commented Sep 27, 2014

This pull request supersedes #647 and has all commits from there squashed into one big one, including a NEWS entry.


This turns fatal errors generated from calls to methods on a non-object into E_RECOVERABLE_ERRORs.

Example

set_error_handler(function($code, $message) {
  var_dump($code, $message);
});

$x= null;
var_dump($x->method());
echo "Alive\n";

The above produces the following output:

int(4096)
string(50) "Call to a member function method() on a non-object"
NULL
Alive

For details see https://wiki.php.net/rfc/catchable-call-to-member-of-non-object

@thekid
Copy link
Contributor Author

thekid commented Sep 27, 2014

@datibbaw - can you check if this is mergeable like this? Thanks in advance!

@Majkl578
Copy link
Contributor

and has all commits from there squashed into one big one, including a NEWS entry.

Are you sure? Looking at the diff, there are only new tests added, no changed to the engine etc.

Changed ZEND_INIT_METHOD_CALL to raise an E_RECOVERABLE_ERROR and handle
error handler outcome, returning NULL if error handler doesn't terminate
the script.

Adjusted outcome in MySQL / PDO_MySQL and ext/date
Added various examples and tests
Added tests for indirect calls - see http://news.php.net/php.internals/73823
Added tests verifying method calls on non-objects work inside eval()
Originally developed inside php#647
@thekid thekid force-pushed the rfc/catchable-call-to-member-of-non-object branch from ac9b9ec to ac2ede7 Compare September 27, 2014 19:29
@thekid
Copy link
Contributor Author

thekid commented Sep 27, 2014

Are you sure?

Thanks for catching that. Here we go:)

@datibbaw
Copy link
Contributor

datibbaw commented Oct 5, 2014

Sorry for taking a while.

There don't seem to be test cases that touch expressions as these:

echo 'foo' . $x->bar() . 'baz'; // nothing
echo 'foo', $x->bar(), 'baz'; // only 'foo'

@thekid
Copy link
Contributor Author

thekid commented Oct 5, 2014

@datibbaw - here we go; I added tests verifying:

echo 'Before', $x->method(), 'After';
echo 'Before'.$x->method().'After';
echo $array[$x->method()];
$array= [$x->method() => 'OK'];

When caught and handled via an error handler, the code above behaves as if NULL was in place of the method call. When unhandled, the script terminates.

@thekid
Copy link
Contributor Author

thekid commented Oct 5, 2014

Of course, since I set this up, the branch has diverged from master in a way that it won't cleanly apply anymore. I see these options:

  • I merge master into this branch at the cost of not being able to rebase and squash commits into one anymore (this has failed for me every single time I've tried leaving back a big mess, I'm probably not skilled enough with git here)
  • The conflict (in ext/date/tests/bug67118.phpt at the time of writing) is resolved manually by using the version from master
  • I create a new clean branch, and a new pull request
  • I merge, then upload the diff as a gist and link to it from here together with a commit message. This is applied with patch -p1 by whomever merges this and the commit message is copy&pasted from here.

@hikari-no-yume
Copy link
Contributor

Merging master in would not stop you rebasing, I'm sure.

@datibbaw
Copy link
Contributor

datibbaw commented Oct 5, 2014

Ugh, why did the numbers have to look so alike to my sleepy eyes? :(

In any case, a combination of your previous pull and this one was merged just now.

@thekid
Copy link
Contributor Author

thekid commented Oct 5, 2014

👍

Checked out master, ran the tests.

$ make test TESTS=Zend/tests/*non-objects*phpt
# ...
=====================================================================
PHP         : /devel/php-src/sapi/cli/php
PHP_SAPI    : cli
PHP_VERSION : 7.0.0-dev
ZEND_VERSION: 2.8.0-dev
PHP_OS      : Linux - Linux precise32 3.2.0-23-generic-pae #36-Ubuntu SMP Tue Apr 10 22:19:09 UTC 2012 i686
INI actual  : /devel/php-src/tmp-php.ini
More .INIs  :
CWD         : /devel/php-src
Extra dirs  :
VALGRIND    : Not used
=====================================================================
Running selected tests.
PASS Catch method calls on non-objects raise recoverable errors [Zend/tests/methods-on-non-objects-args-catch.phpt]
PASS Catch method calls on non-objects inside array access [Zend/tests/methods-on-non-objects-array-access.phpt]
PASS Catch method calls on non-objects inside array creation [Zend/tests/methods-on-non-objects-array-creation.phpt]
PASS Catch method calls on non-objects as argument [Zend/tests/methods-on-non-objects-as-arg.phpt]
PASS call_user_func() in combination with "Call to a member function method() on a non-object" [Zend/tests/methods-on-non-objects-call-user-func.phpt]
PASS Catch method calls on non-objects raise recoverable errors [Zend/tests/methods-on-non-objects-catch.phpt]
PASS Catch chained method calls on non-objects raise recoverable errors [Zend/tests/methods-on-non-objects-chain.phpt]
PASS Catch method calls on non-objects inside concatenation [Zend/tests/methods-on-non-objects-concat.phpt]
PASS Catch method calls on non-objects with dynamic lookups [Zend/tests/methods-on-non-objects-dynamic.phpt]
PASS Indirect call inside eval to member function on non-object [Zend/tests/methods-on-non-objects-eval.phpt]
PASS Catch method calls on non-objects inside echo [Zend/tests/methods-on-non-objects-in-echo.phpt]
PASS Catch method calls on non-objects with nested dynamic calls [Zend/tests/methods-on-non-objects-nested-calls-dyn.phpt]
PASS Catch method calls on non-objects with nested calls to new [Zend/tests/methods-on-non-objects-nested-calls-new.phpt]
PASS Catch method calls on non-objects with nested non-compile-time-resolveable calls [Zend/tests/methods-on-non-objects-nested-calls-nonct.phpt]
PASS Catch method calls on non-objects with nested calls to namespaced functions with core counterparts [Zend/tests/methods-on-non-objects-nested-calls-ns.phpt]
PASS Catch method calls on non-objects with nested calls to static methods [Zend/tests/methods-on-non-objects-nested-calls-static.phpt]
PASS Catch method calls on non-objects with nested function and method calls [Zend/tests/methods-on-non-objects-nested-calls.phpt]
PASS Catch method calls on non-objects without using return value [Zend/tests/methods-on-non-objects-return-unused.phpt]
PASS Convert errors to exceptions from method calls on non-objects raise recoverable errors [Zend/tests/methods-on-non-objects-throw.phpt]
PASS usort() in combination with "Call to a member function method() on null" [Zend/tests/methods-on-non-objects-usort.phpt]
PASS Method calls on non-objects raise recoverable errors [Zend/tests/methods-on-non-objects.phpt]
=====================================================================
Number of tests :   21                21
Tests skipped   :    0 (  0.0%) --------
Tests warned    :    0 (  0.0%) (  0.0%)
Tests failed    :    0 (  0.0%) (  0.0%)
Expected fail   :    0 (  0.0%) (  0.0%)
Tests passed    :   21 (100.0%) (100.0%)
---------------------------------------------------------------------
Time taken      :    1 seconds
=====================================================================

Looking good! Thanks for merging, @datibbaw!

@thekid thekid closed this Oct 5, 2014
@thekid thekid deleted the rfc/catchable-call-to-member-of-non-object branch October 5, 2014 23:23
@thekid thekid deleted the rfc/catchable-call-to-member-of-non-object branch October 5, 2014 23:23
@thekid thekid changed the title Implemented the RFC Catchable "Call to a member function bar()..." Implement the RFC Catchable "Call to a member function bar()..." Oct 5, 2014
@laruence
Copy link
Member

laruence commented Oct 7, 2014

Hey, sorry to didn't read the patch before.

there is only one question, the destination opline (while recoverable error occurred) could be very easy to be calculated in compile time(zend_compile_method_call).

maybe it's better to record it at then instead of calculated it in runtime..

like we could insert a ZEND_JMP after INIT_METHOD_CALL to jmp over send args while error occurs. I am not sure whether it's overhead...

@thekid
Copy link
Contributor Author

thekid commented Oct 7, 2014

Hi - not sure this should go at the expense of compile time. It is, after all, an extraordinary and rather unexpected situation we are recovering from. It's okay if that is not super optimized.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants