Это немного поздно для вечеринки, но я не видел этого ответа и только недавно реализовал нечто подобное для класса отладки (для обработки циклических ссылок). Как вы, ребята, можете знать или не знать обычные функции печати, такие как var_export
, с ограниченной или отсутствующей циклической справочной поддержкой.
Как уже отмечалось, spl_object_hash уникален для каждого случая, проблема, с которой я столкнулся, заключается в том, что он ужасен. Не совсем подходит для печати для моего отладчика, так как это что-то вроде 000000006ac56bae0000000044fda36f
, что может быть трудно сравнить с этим 000000006ac56bae0000000044fda35f
. Так как, как указывалось в ОП, мне нужен был только номер экземпляра (мне это действительно нужно было только для каждого класса).
Поэтому для меня самым простым решением было сделать следующее.
$class = get_class( $input );
$hash = spl_object_hash( $input );
if( !isset( $objInstances[ $class ] )){
$objInstances[ $class ] = array();
}
$output = 'object(%s) #%s (%s){%s}'; //class, instance, prop_count, props
if( false === ( $index = array_search($hash, $objInstances[ $class ] ) ) ){
$index = count($objInstances[ $class ]); //set init index for instance
$objInstances[ $class ][] = $hash;
// .... debugging code
$output = 'debugging result.', //sprintf
}else{
$output = sprintf( $output, $class, $index, 0, '#_CIRCULAR_REFRENCE_#');
}
Очевидно, что код отладки намного сложнее, но здесь важно то, что, отслеживая класс и хэш spl в $objInstances
, я могу легко назначить свои собственные номера экземпляров вне класса. Это означает, что мне не нужен некрасивый хак (который влияет на код класса), чтобы получить ссылочный номер. Кроме того, мне не нужно отображать "некрасивый" хэш spl. Во всяком случае мой полный код для этого выводит что-то вроде этого.
$obj = new TestObj();
$obj1 = new TestObj();
$obj->setProProp($obj1);
$obj1->setProProp($obj); //create a circular reference
object(TestObj) #0 (7){
["SOME_CONST":const] => string(10) 'some_const',
["SOMEOTHER_CONST":const] => string(16) 'some_other_const',
["SOME_STATIC":public static] => string(6) 'static',
["_PRO_STATIC":protected static] => string(10) 'pro_static',
["someProp":public] => string(8) 'someProp',
["_pro_prop":protected] => object(TestObj) #1 (7){
["SOME_CONST":const] => string(10) 'some_const',
["SOMEOTHER_CONST":const] => string(16) 'some_other_const',
["SOME_STATIC":public static] => string(6) 'static',
["_PRO_STATIC":protected static] => string(10) 'pro_static',
["someProp":public] => string(8) 'someProp',
["_pro_prop":protected] => object(TestObj) #0 (0){#_CIRCULAR_REFRENCE_#},
["_proProp":protected] => string(7) 'proProp'
},
["_proProp":protected] => string(7) 'proProp'
}
Как видите, очень легко увидеть, откуда взялась object(TestObj) #0 (0){#_CIRCULAR_REFRENCE_#}
. Я хотел сохранить этот код отладки как можно ближе к нативному var_dump
который выводит это.
object(TestObj)#7 (3) {
["someProp"]=> string(8) "someProp"
["_pro_prop":protected]=> object(TestObj)#10 (3) {
["someProp"]=> string(8) "someProp"
["_pro_prop":protected]=> *RECURSION*
["_proProp":protected]=> string(7) "proProp"
}
["_proProp":protected]=> string(7) "proProp"
}
Разница здесь в том, что мне нужно возвращать в виде строки, а не выводить в браузер. Я также хотел иметь возможность показывать константы класса, статические свойства и частные свойства (с флагами, чтобы изменить то, что выводит отладчик, и предел глубины). И я хотел получить немного больше информации о том, что такое циклическая ссылка, а не просто *RECURSION*
, которая мне ничего не говорит.
Надеюсь, это поможет кому-то в будущем.
Вот полный код моего класса отладки, вы можете найти его в строке # 300
https://github.com/ArtisticPhoenix/Evo/blob/master/Evo/Debug.php