On 01/08/2015 01:06, Rowan Collins wrote:
On 1 August 2015 00:36:58 BST, Stanislav Malyshev <smalys...@gmail.com> wrote:
DEBUG_BACKTRACE_IGNORE_ARGS in a debug_backtrace() call. IIRC the
object of called methods is already excluded (equivalent to masking
out DEBUG_PROVIDE_OBJECT) so what's left is all strings.
I'm not sure how you arrived at the conclusion that all arguments in
backtrace are strings. Arguments can be of any type. When printed, they
are converted to strings, but they are not strings when stored.
I'll have to recheck when I have more time, and something better than a phone
to type on, but from memory, the backtrace which can be retrieved from an
exception includes the same information as debug_backtrace(false), that is:
- function: string
- line: integer
- file: string
- class: string
- type: string
- args: array
Of these 6 items, it is only 'args' that can contain an object of any kind, so
without this item, the data would be serializable. This would be equivalent to
debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS).
If any of these items (other than args) are stored in memory in a different
form (which doesn't seem likely to me), that form is completely inaccessible to
the user, so converting to string during serialization would effectively be
lossless. (Or, pre-converting would have zero BC break.) Similarly, if
additional details are stored, those details are inaccessible, so removing them
has no impact on any existing (userland) code.
I just double-checked this. You can see that there is not even an
internal reference to objects which were $this in the stack trace,
because the object can be garbage collected separately from the
exception. http://3v4l.org/hOYb9
So, as I said, no object will be implicitly attached to the exception
anywhere other than the 'args' key of the backtrace. Obviously, people
can attach object references wherever they like, but without this
implicit gathering of objects from the entire environment,
"serialize(new Exception)" would be a safe operation.
Slightly abbreviated version:
class Example {
private $label;
public function __construct($label) {
$this->label = $label;
}
public function __sleep() {
echo "Attempt to serialize object with label $this->label\n";
return array('label');
}
public function __destruct() {
echo "Refcount reached zero for object with label $this->label\n";
}
public function throwSomething($unused_parameter) {
throw new Exception;
}
}
$target = new Example('Target of method call');
$parameter = new Example('Parameter passed but never actually used');
try {
$target->throwSomething($parameter);
}
catch ( Exception $e ) {
// Serialize exception, will attempt to serialize $parameter but
not $target
var_dump(serialize($e));
// Destroy $target, as there are no other references to it
unset($target);
// Attempt to do the same for $parameter, but Exception holds a
reference
unset($parameter);
}
echo "-- PHP process cleanup begins here --\n";
// $parameter will have its destructor fired once $e goes out of scope
and relinquishes its reference
Regards,
--
Rowan Collins
[IMSoP]
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php