0

I'm learning my way into some more advanced programming with PHP.

I've seen that calling an non-existent method produces "call to undefined method" error.

PHP being quite flexible is there a technique that allows to intercept this error ? If so, how is this usually done ?

Edit: To clarify, I want to actually do something when the error occurs like send a reply back, not necessarily prevent it. Forget to mention that this is in the context of a class. Of course, methods only apply in the context of a class ;)

James P.
  • 19,313
  • 27
  • 97
  • 155
  • 1
    You might want to look at this, which also covers fatal errors: http://stackoverflow.com/a/2146171/1125956. You could have the error be logged in the shutdown function, and the user redirected to an error page, for example. – Connor Peet Aug 19 '13 at 02:01
  • @SteAp It's not about preventing, it's about actually doing something when the error occurs. Say send a friendly message back to the caller to say what's happened. Could be useful in a framework. – James P. Aug 19 '13 at 03:07
  • @SteAp Just had a quick skim through the link. It starts off by `is there any way that I can ignore functions...`. Definitely not what I want. Will take note of answers though. – James P. Aug 19 '13 at 03:10
  • @Jack I actually want the class to handle this. Explanation given below. – James P. Aug 19 '13 at 03:37
  • Does an error actually kill the process ? I'm doing calls through ajax so it's simply messing up the response. – James P. Aug 19 '13 at 03:40
  • Ok thanks guys. Lot's of good info here. Going to put all of this to good use =D . – James P. Aug 19 '13 at 03:47

3 Answers3

1

Yes, it's possible to trap calls to undefined methods of classes using magic methods:

You need to implement the __call() and/or __callStatic() methods as defined here.

Suppose you have a simple class CCalculationHelper with just a few methods:

class CCalculationHelper {

  static public function add( $op1, $op2 ) {

    assert(  is_numeric( $op1 ));
    assert(  is_numeric( $op2 ));

    return ( $op1 + $op2 );

  }

  static public function diff( $op1, $op2 ) {

    assert(  is_numeric( $op1 ));
    assert(  is_numeric( $op2 ));

    return ( $op1 - $op2 );

  }

}

At a later point of time, you need to enhance this class by multiplication or division. Instead of using two explicit methods, you might use a magic method, which implements both operations:

class CCalculationHelper {

  /**  As of PHP 5.3.0  */
  static public function __callStatic( $calledStaticMethodName, $arguments ) {

    assert( 2 == count( $arguments  ));
    assert( is_numeric( $arguments[ 0 ] ));
    assert( is_numeric( $arguments[ 1 ] ));

    switch( $calledStaticMethodName ) {

       case 'mult':
          return $arguments[ 0 ] * $arguments[ 1 ];
          break;

       case 'div':
          return $arguments[ 0 ] / $arguments[ 1 ];
          break;

    }

    $msg = 'Sorry, static method "' . $calledStaticMethodName . '" not defined in class "' . __CLASS__ . '"';
    throw new Exception( $msg, -1 );

  }

  ... rest as before... 

}

Call it like so:

  $result = CCalculationHelper::mult( 12, 15 );
SteAp
  • 11,853
  • 10
  • 53
  • 88
  • Right. So it would be possible to get the call and send a reply back ? Perhaps using some kind of callback pattern. – James P. Aug 19 '13 at 03:11
  • 1
    @JamesPoulson Yes, that's definitely possible. I've enhanced my answer. – SteAp Aug 19 '13 at 13:49
1

If you mean how to intercept non-existent method in a your custom class, you can do something like this

<?php
    class CustomObject {
        public function __call($name, $arguments) {
            echo "You are calling this function: " . 
            $name . "(" . implode(', ', $arguments) . ")";
        }
    }

    $obj = new CustomObject();
    $obj->HelloWorld("I love you");
?>

Or if you want to intercept all the error

function error_handler($errno, $errstr, $errfile, $errline) {
    // handle error here.
    return true;
}
set_error_handler("error_handler");
Ja͢ck
  • 170,779
  • 38
  • 263
  • 309
invisal
  • 11,075
  • 4
  • 33
  • 54
  • Whoops. Did not mention I was on about classes so thanks for giving this a thought. Yes, the first possibility is along the lines of what I'm interested in. I suppose the error_handler is along the same lines as intercepting uncaught exceptions ? Don't think I could use that as intended. – James P. Aug 19 '13 at 03:14
1

Seeing how you don't wish to recover from these fatal errors, you can use a shutdown handler:

function on_shutdown()
{
    if (($last_error = error_get_last()) {
        // uh oh, an error occurred, do last minute stuff
    }
}

register_shutdown_function('on_shutdown');

The function is called at the end of your script, regardless of whether an error occurred; a call to error_get_last() is made to determine that.

Ja͢ck
  • 170,779
  • 38
  • 263
  • 309
  • Can definitely use this. I realize my question may seem vague so to explain things I'd like an application to recover if a call goes through on a method that doesn't exist. Say for example a situation where the callee expects a JSON response. Can't have something an Exception and an error would also mess things up so, ideally, a standardized response could be sent to simply say, "inexistant method. Check application configuration.". – James P. Aug 19 '13 at 03:34
  • 1
    @JamesPoulson Then you could use inheritance and let the parent class take care of handling `__call()`. – Ja͢ck Aug 19 '13 at 03:42
  • That's a good idea :) . Have a standard method à la template pattern in an abstract class or something. Yes, `__call()` does seem to fit here. – James P. Aug 19 '13 at 03:45