19

I would like to write a test using simpleTest that would fail if the method I'm testing results in a PHP E_NOTICE "undefined index : foo".

I tried expectError() and expectException() without success. The simpleTest webpage indicate that simpleTest isn't able to catch compile time PHP errors, but E_NOTICE seems to be a run time error.

Is there a way to catch such an error and makes my test fail if so ?

pixelastic
  • 5,138
  • 6
  • 24
  • 29

4 Answers4

21

That wasn't really easy but I finally managed to catch the E_NOTICE error I wanted. I needed to override the current error_handler to throw an exception that I will catch in a try{} statement.

function testGotUndefinedIndex() {
    // Overriding the error handler
    function errorHandlerCatchUndefinedIndex($errno, $errstr, $errfile, $errline ) {
        // We are only interested in one kind of error
        if ($errstr=='Undefined index: bar') {
            //We throw an exception that will be catched in the test
            throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
        }
        return false;
    }
    set_error_handler("errorHandlerCatchUndefinedIndex");

    try {
        // triggering the error
        $foo = array();
        echo $foo['bar'];
    } catch (ErrorException $e) {
        // Very important : restoring the previous error handler
        restore_error_handler();
        // Manually asserting that the test fails
        $this->fail();
        return;
    }

    // Very important : restoring the previous error handler
    restore_error_handler();
    // Manually asserting that the test succeed
    $this->pass();
}

This seems a little overly complicated having to redeclare the error handler to throw an exception just to catch it. The other hard part was correctly restoring the error_handler both when an exception was catched and no error occured, otherwise it just messes with SimpleTest error handling.

pixelastic
  • 5,138
  • 6
  • 24
  • 29
  • 11
    How awful language that is! – m93a Mar 13 '15 at 18:53
  • 1
    If you provide E_NOTICE as a 2nd parameter to set_error_handler it will only handle notices. "Can be used to mask the triggering of the _error_handler_ function just like the error_reporting ini setting controls which errors are shown. Without this mask set the _error_handler_ will be called for every error regardless to the setting of the error_reporting setting." – nick Jan 24 '18 at 19:21
6

There really isn't a need to catch the notice error. One could also test the outcome of 'array_key_exists' and then proceed from there.

http://www.php.net/manual/en/function.array-key-exists.php

Test for false and have it fail.

Robert Brisita
  • 5,461
  • 3
  • 36
  • 35
  • If down voting, please explain why. – Robert Brisita Mar 10 '17 at 14:00
  • 5
    There is a case when you are projecting an array into another array. You don't want to test for each individual map, you want to catch the case where any one of the mapping fails. This would be much easier with exceptions. – CMCDragonkai Mar 15 '17 at 04:03
3

You'll never catch it within the try-catch block, luckily we have set_error_handler():

<?php
function my_handle(){}
set_error_handler("my_handle");
echo $foo["bar"];
?>

You can do anything you want inside my_handle() function, or just leave it empty to silence the notice, although, it's not recommended. A normal handler should be like this:

function myErrorHandler($errno, $errstr, $errfile, $errline)
John Lee
  • 39
  • 2
  • Best answer that is actually simple and works, unsure why it has no upvotes... but mine <3 – kungfooman Feb 05 '20 at 17:52
  • because it doesn't mention how to restore the previous error handler for errors other than the one you are trying to catch. – Joel M Apr 23 '22 at 16:29
0

Many solutions to handling at sign E_NOTICE errors ignore all E_NOTICE errors. To ignore just errors due to use of at signs, do this in your set_error_handler callback function:

if (error_reporting()==0 && $errno==E_NOTICE)
    return; // Ignore notices for at sign

An example of an important E_NOTICE that should not be ignored is this:

$a=$b;

because $b is undefined.

David Spector
  • 1,520
  • 15
  • 21