I've just implemented a custom error with trigger_error()
, but the problem is that the line that calls trigger_error()
is shown as the offending line in the call stack trace, instead of the calling line.
<?php
trait ClassProtection {
public function __get($name) {
$class_name = get_called_class();
trigger_error("Public property {$class_name}::\${$name} does not exist", E_USER_ERROR);
}
public function __set($name, $value) {
$class_name = get_called_class();
trigger_error("Public property {$class_name}::\${$name} does not exist and automatic creation has been disabled", E_USER_ERROR);
}
}
class SomeClass {
use ClassProtection;
public $foo = 1;
protected $bar = 2;
private $baz = 3;
}
$sc = new SomeClass;
// Try to access existing public property: should work
var_dump($sc->foo);
$sc->foo = 11;
// Try to access existing protected property: should not work - fatal error
var_dump($sc->bar);
$sc->bar = 12;
// Try to access existing private property: should not work - fatal error
var_dump($sc->baz);
$sc->baz = 13;
// Try to create new public property: should not work - fatal error
$sc->qux = 14;
var_dump($sc->qux);
With the line //use ClassProtection;
commented, it produces the following:
C:\>php test_class_protection.php
int(1)
PHP Fatal error: Cannot access protected property SomeClass::$bar in C:\test_class_protection.php on line 28
PHP Stack trace:
PHP 1. {main}() C:\test_class_protection.php:0
Fatal error: Cannot access protected property SomeClass::$bar in C:\test_class_protection.php on line 28
Call Stack:
0.0000 127344 1. {main}() C:\test_class_protection.php:0
With the line use ClassProtection;
uncommented, it produces the following:
C:\>php test_class_protection.php
int(1)
PHP Fatal error: Public property SomeClass::$bar does not exist in C:\test_class_protection.php on line 5
PHP Stack trace:
PHP 1. {main}() C:\test_class_protection.php:0
PHP 2. SomeClass->__get($name = 'bar') C:\test_class_protection.php:28
PHP 3. trigger_error('Public property SomeClass::$bar does not exist', 256) C:\test_class_protection.php:5
Fatal error: Public property SomeClass::$bar does not exist in C:\test_class_protection.php on line 5
Call Stack:
0.0000 127648 1. {main}() C:\test_class_protection.php:0
0.0000 128904 2. SomeClass->__get(string(3)) C:\test_class_protection.php:28
0.0000 129128 3. trigger_error(string(46), long) C:\test_class_protection.php:5
Note that there are two extra lines in there which are not useful, and are in fact distracting, when debugging. I want the second error to look like the first, except with the message customised.
I seem to remember from when I used to work with Perl that it had some sort of trusted code mechanism that prevented code marked as trusted from appearing in a stack trace. Is there any way in PHP to hide the last one or two calls in the call stack trace without rewriting the whole error handling routine so that it looks like a standard PHP error happened on the correct line?
Ideally, I'd like to get a copy of the stack trace, modify it slightly and return it to PHP's standard error handler.