Skip to content

[wip] [Debug] Improvements, compat and Object tracer #12159

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions src/Symfony/Component/Debug/Resources/ext/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,88 @@ array(3) {
*/
```

symfony_debug_object_tracer_set_logger(Psr\Log\LoggerInterface $logger)
---------------------------------------------------------

Collector for object traces. Object traces is a tracer - enabled when a logger object is passed to symfony_debug_set_logger() - that traces objects creation / cloning and destruction from a PHP instance.
The PSR3 Logger is used to log object traces, the debug() method is used, receiving a general message, and as context, the object class, the object handle, the filename and line where happening (except in shutdown sequence) and the type of event beeing logged : SYMFONY_DEBUG_OBJECT_TRACE_TYPE_NEW (object creation), SYMFONY_DEBUG_OBJECT_TRACE_TYPE_CLONE (object clone) or SYMFONY_DEBUG_OBJECT_TRACE_TYPE_DESTROY (object destruction).

```php
class TestLog implements Psr\Log\LoggerInterface {
public function emergency($message, array $context = array()) { }
public function alert($message, array $context = array()) { }
public function critical($message, array $context = array()) { }
public function error($message, array $context = array()) { }
public function warning($message, array $context = array()) { }
public function notice($message, array $context = array()) { }
public function info($message, array $context = array()) { }
public function debug($message, array $context = array()) { printf("$message \n"); }
public function log($level, $message, array $context = array()) { }
}

/* Exemple filtering only on object destruction */
class LogFilter extends TestLog
{
public function debug($message, array $context = array())
{
if($context['trace_type'] & SYMFONY_DEBUG_OBJECT_TRACE_TYPE_DESTROY) {
printf('destroying');
}
}
}

$log = new TestLog;
symfony_debug_object_tracer_set_logger($log);

$a = new StdClass;

$b = clone $a;

unset($b);

/* This will output :
Creating an object of class stdClass in foo.php:15
Cloning object #2 of class stdClass in foo.php:17
Destroying object #3 of class stdClass at foo.php:19
Destroying object #2 of class stdClass at [no active file]:0
*/
```

symfony_debug_get_error_handler() - symfony_debug_get_error_handlers()
----------------------------------------------------------

Simply dumps the current user error handler(s).

```php

function my_eh() { }

set_error_handler(function () { });
set_error_handler('my_eh');

var_dump(symfony_debug_get_error_handler());
var_dump(symfony_debug_get_error_handlers());

/*
string(5) "my_eh"

array(2) {
[0]=>
object(Closure)#1 (0) {
}
[1]=>
string(5) "my_eh"
}
*/

```

symfony_debug_enable_var_dumper_dump()
--------------------------------------

Replaces PHP's var_dump() function by Symfony\\Component\\VarDumper\\VarDumper::dump();
Supports Xdebug.

Usage
-----

Expand Down
112 changes: 111 additions & 1 deletion src/Symfony/Component/Debug/Resources/ext/php_symfony_debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,20 @@
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* Julien PAULI <jpauli@php.net>
*/

#ifndef PHP_SYMFONY_DEBUG_H
#define PHP_SYMFONY_DEBUG_H

#include "sensiolabs_php_compat.h"

extern zend_module_entry symfony_debug_module_entry;
#define phpext_symfony_debug_ptr &symfony_debug_module_entry
#ifdef COMPILE_DL_SYMFONY_DEBUG
zend_module_entry *get_module(void);
#endif

#define PHP_SYMFONY_DEBUG_VERSION "2.7"

Expand All @@ -28,9 +35,13 @@ extern zend_module_entry symfony_debug_module_entry;
#endif

ZEND_BEGIN_MODULE_GLOBALS(symfony_debug)
intptr_t req_rand_init;
void (*old_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args);
zval *debug_bt;
zval *psr3_logger;
zend_function *psr3_logger_cache;
zend_function *php_var_dump;
intptr_t req_rand_init;
zend_bool in_logger;
ZEND_END_MODULE_GLOBALS(symfony_debug)

PHP_MINIT_FUNCTION(symfony_debug);
Expand All @@ -43,14 +54,113 @@ PHP_GSHUTDOWN_FUNCTION(symfony_debug);

PHP_FUNCTION(symfony_zval_info);
PHP_FUNCTION(symfony_debug_backtrace);
PHP_FUNCTION(symfony_debug_object_tracer_set_logger);
PHP_FUNCTION(symfony_debug_get_error_handlers);
PHP_FUNCTION(symfony_debug_get_error_handler);
PHP_FUNCTION(symfony_debug_enable_var_dumper_dump);

static char *_symfony_debug_memory_address_hash(void * TSRMLS_DC);
static const char *_symfony_debug_zval_type(zval *);
static const char* _symfony_debug_get_resource_type(long TSRMLS_DC);
static int _symfony_debug_get_resource_refcount(long TSRMLS_DC);
static int symfony_debug_post_deactivate(void);
static const char sensiolabs_logo[] = "<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHYAAAAUCAMAAABvRTlyAAAAz1BMVEUAAAAAAAAAAAAsThWB5j4AAACD6T8AAACC6D+C6D6C6D+C6D4AAAAAAACC6D4AAAAAAACC6D8AAAAAAAAAAAAAAAAAAAAAAACC6D4AAAAAAAAAAACC6D4AAAAAAAAAAAAAAAAAAAAAAACC6D8AAACC6D4AAAAAAAAAAAAAAAAAAACC6D8AAACC6D6C6D+B6D+C6D+C6D+C6D8AAACC6D6C6D4AAACC6D/K/2KC6D+B6D6C6D6C6D+C6D8sTxUyWRhEeiEAAACC6D+C5z6B6D7drnEVAAAAQXRSTlMAE3oCNSUuDHFHzxaF9UFsu+irX+zlKzYimaJXktyOSFD6BolxqT7QGMMdarMIpuO28r9EolXKgR16OphfXYd4V14GtB4AAAMpSURBVEjHvVSJctowEF1jjME2RziMwUCoMfd9heZqG4n//6buLpJjkmYm03byZmxJa2nf6u2uQcG2bfhqRN4LoTKBzyGDm68M7mAwcOEdjo4zhA/Rf9Go/CVtTgiRhXfIC3EDH8F/eUX1/9KexRo+QgOdtHDsEe/sM7QT32/+K61Z1LFXcXJxN4pTbu1aTQUzuy2PIA0rDo0/0Aa5XFaJvKaVTrubywXvaa1Wq4Vu/Snr3Y7Aojh4VccwykW2N2oQ8wmjyut6+Q1t5ywIG5Npj1sh5E0B7YOzFDjfuRfaOh3O+MbbVNfTWS9COZk3Obd2su5d0a6IU9KLREbw8gEehWSr1r2sPWciXLG38r5NdW0xu9eioU87omjC9yNaMi5GNf6WppVSOqXCFkmCvMB3p9SROLoYQn5pDgQOujA1xjYvqH+plUdkwnmII8VxR/PKYkrfLLomhVlE3b/LhNbNr7hp0H2JaOc4v8dFB58HSsFTSafaqtY1sT3GO8wsy5rhokYPlRJdjPMajyYqTt1EHF/2uqSWQWmAjCUSmQ1MS3g8Btf1XOsy7YIC0CB1b5Xw1Vhba0zbxiCAQLH9TNPmHJXQUtJAN0KcDsoqLxsNvJrJExa7mKIdp2lRE2WexiS4pqWk/0jROlw6K6bV9YOBDGAuqMJ0bnuUKGB0L27bxgRhGEbzihbhxxXaQC88Vkwq8ldCi86RApWUb0Q+4VDosBCc+1s81lUdnBavH4Zp2mm3O44USwOfvSo9oBiwpFg71lMS1VKJLKljS3j9p+fOTvXXlsSNuEv6YPaZda9uRope0VJfKdo7fPiYfSmvFjXQbkhY0d9hCbBWIktRgEDieDhf1N3wbbkmNNgRy8hyl620yGQat/grV3HMpc2HDKTVmOPFz6ylPCKt/nXcAyV260jaAowwIW0YuBzrOgb/KrddZS9OmJaLgpWK4JX2DDuklcLZSDGcn8Vmx9YDNvT6UsjyBApRyFQVX7Vxm9TGxE16nmfRd8/zQoDmggQOTRh5Hv8pMt9Q/L2JmSwkMCE7dA4BuDjHJwfu0Om4QAhOjrN5XkIatglfiN/bUPdCQFjTYgAAAABJRU5ErkJggg==\">";

void symfony_debug_error_cb(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args);

typedef enum {
SYMFONY_DEBUG_OBJECT_TRACE_TYPE_NEW,
SYMFONY_DEBUG_OBJECT_TRACE_TYPE_CLONE,
SYMFONY_DEBUG_OBJECT_TRACE_TYPE_DESTROY
} symfony_debug_object_trace_type;

typedef struct _symfony_debug_object_trace {
zend_class_entry *ce;
zend_object_handle handle;
const char*filename;
char *msg;
uint lineno;
symfony_debug_object_trace_type trace_type;
} symfony_debug_object_trace;

static symfony_debug_object_trace _symfony_debug_new_object_trace(zend_class_entry *ce, zend_object_handle handle, symfony_debug_object_trace_type type TSRMLS_DC);
static char *_symfony_debug_memory_address_hash(void * TSRMLS_DC);
static const char* _symfony_debug_get_resource_type(long TSRMLS_DC);
static int _symfony_debug_get_resource_refcount(long TSRMLS_DC);
static zend_object_value _symfony_debug_obj_handlers_clone_handler(zval *obj TSRMLS_DC);
static void _symfony_debug_log_using_psr3_logger(symfony_debug_object_trace trace TSRMLS_DC);
static int _symfony_debug_opcode_handler_new(ZEND_OPCODE_HANDLER_ARGS);

void symfony_debug_error_cb(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args);

#define HANDLER_LIST_M(m) if(handlers->m != default_handlers->m) { add_next_index_string(modified_object_handlers, #m, 1); }

#if IS_AT_LEAST_PHP_54
#define OBJ_HANDLERS_CHECK \
HANDLER_LIST_M(add_ref) \
HANDLER_LIST_M(del_ref) \
HANDLER_LIST_M(clone_obj) \
HANDLER_LIST_M(read_property) \
HANDLER_LIST_M(write_property) \
HANDLER_LIST_M(read_dimension) \
HANDLER_LIST_M(write_dimension) \
HANDLER_LIST_M(get_property_ptr_ptr) \
HANDLER_LIST_M(get) \
HANDLER_LIST_M(set) \
HANDLER_LIST_M(has_property) \
HANDLER_LIST_M(unset_property) \
HANDLER_LIST_M(has_dimension) \
HANDLER_LIST_M(unset_dimension) \
HANDLER_LIST_M(get_properties) \
HANDLER_LIST_M(get_method) \
HANDLER_LIST_M(call_method) \
HANDLER_LIST_M(get_constructor) \
HANDLER_LIST_M(get_class_entry) \
HANDLER_LIST_M(get_class_name) \
HANDLER_LIST_M(compare_objects) \
HANDLER_LIST_M(cast_object) \
HANDLER_LIST_M(count_elements) \
HANDLER_LIST_M(get_debug_info) \
HANDLER_LIST_M(get_closure) \
HANDLER_LIST_M(get_gc)
#else
#define OBJ_HANDLERS_CHECK \
HANDLER_LIST_M(add_ref) \
HANDLER_LIST_M(del_ref) \
HANDLER_LIST_M(clone_obj) \
HANDLER_LIST_M(read_property) \
HANDLER_LIST_M(write_property) \
HANDLER_LIST_M(read_dimension) \
HANDLER_LIST_M(write_dimension) \
HANDLER_LIST_M(get_property_ptr_ptr) \
HANDLER_LIST_M(get) \
HANDLER_LIST_M(set) \
HANDLER_LIST_M(has_property) \
HANDLER_LIST_M(unset_property) \
HANDLER_LIST_M(has_dimension) \
HANDLER_LIST_M(unset_dimension) \
HANDLER_LIST_M(get_properties) \
HANDLER_LIST_M(get_method) \
HANDLER_LIST_M(call_method) \
HANDLER_LIST_M(get_constructor) \
HANDLER_LIST_M(get_class_entry) \
HANDLER_LIST_M(get_class_name) \
HANDLER_LIST_M(compare_objects) \
HANDLER_LIST_M(cast_object) \
HANDLER_LIST_M(count_elements) \
HANDLER_LIST_M(get_debug_info) \
HANDLER_LIST_M(get_closure)
#endif

#define LOG_TRACE(class_entry, obj_handle, trace_type) do { \
if (SYMFONY_DEBUG_G(psr3_logger)) { \
symfony_debug_object_trace trace; \
trace = _symfony_debug_new_object_trace((class_entry), (obj_handle), (trace_type) TSRMLS_CC); \
\
_symfony_debug_log_using_psr3_logger(trace TSRMLS_CC); \
} \
} while (0);

#ifdef ZTS
#define SYMFONY_DEBUG_G(v) TSRMG(symfony_debug_globals_id, zend_symfony_debug_globals *, v)
#else
Expand Down
Loading