diff --git a/tests/var_dump.phpt b/tests/var_dump.phpt new file mode 100644 index 0000000..0aacb43 --- /dev/null +++ b/tests/var_dump.phpt @@ -0,0 +1,315 @@ +--TEST-- +Test V8::executeString() : var_dump +--SKIPIF-- + +--INI-- +date.timezone=UTC +--FILE-- +obj = new Foo; + +$phptypes = $v8->phptypes = array( + "null" => NULL, + "bool" => true, + "string" => "string", + "uint" => 1, + "int" => -1, + "number" => 3.141592654, + "date" => new DateTime('September 27, 1976 09:00:00 UTC', new DateTimeZone('UTC')), + //"regexp" => new Regexp('/regexp/'), /* no native PHP regex type */ + "array" => array(1,2,3), + "object" => array( "field" => "foo" ), + "function" => (function ($x) { return $x; }), + "phpobject" => new Foo +); + +echo "---- PHP var_dump of PHP object ----\n"; +var_dump($phptypes); + +try { + var_dump($v8->executeString($JS, 'var_dump.js')); +} catch (V8JsScriptException $e) { + echo "Error!\n"; + var_dump($e); +} +?> +===EOF=== +--EXPECTF-- +---- PHP var_dump of PHP object ---- +array(11) { + ["null"]=> + NULL + ["bool"]=> + bool(true) + ["string"]=> + string(6) "string" + ["uint"]=> + int(1) + ["int"]=> + int(-1) + ["number"]=> + float(3.141592654) + ["date"]=> + object(DateTime)#%d (3) { + ["date"]=> + string(19) "1976-09-27 09:00:00" + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(3) "UTC" + } + ["array"]=> + array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + } + ["object"]=> + array(1) { + ["field"]=> + string(3) "foo" + } + ["function"]=> + object(Closure)#%d (1) { + ["parameter"]=> + array(1) { + ["$x"]=> + string(10) "" + } + } + ["phpobject"]=> + object(Foo)#%d (1) { + ["field"]=> + string(3) "php" + } +} +--- JS var_dump of PHP object ---- +array (11) { + ["null"] => + NULL + ["bool"] => + bool(true) + ["string"] => + string(6) "string" + ["uint"] => + int(1) + ["int"] => + int(-1) + ["number"] => + float(3.141593) + ["date"] => + object(DateTime)#%d (18) { + ["createFromFormat"] => + object(Closure)#%d { + function () { [native code] } + } + ["getLastErrors"] => + object(Closure)#%d { + function () { [native code] } + } + ["format"] => + object(Closure)#%d { + function () { [native code] } + } + ["modify"] => + object(Closure)#%d { + function () { [native code] } + } + ["add"] => + object(Closure)#%d { + function () { [native code] } + } + ["sub"] => + object(Closure)#%d { + function () { [native code] } + } + ["getTimezone"] => + object(Closure)#%d { + function () { [native code] } + } + ["setTimezone"] => + object(Closure)#%d { + function () { [native code] } + } + ["getOffset"] => + object(Closure)#%d { + function () { [native code] } + } + ["setTime"] => + object(Closure)#%d { + function () { [native code] } + } + ["setDate"] => + object(Closure)#%d { + function () { [native code] } + } + ["setISODate"] => + object(Closure)#%d { + function () { [native code] } + } + ["setTimestamp"] => + object(Closure)#%d { + function () { [native code] } + } + ["getTimestamp"] => + object(Closure)#%d { + function () { [native code] } + } + ["diff"] => + object(Closure)#%d { + function () { [native code] } + } + ["date"] => + string(19) "1976-09-27 09:00:00" + ["timezone_type"] => + int(3) + ["timezone"] => + string(3) "UTC" + } + ["array"] => + array(3) { + [0] => + int(1) + [1] => + int(2) + [2] => + int(3) + } + ["object"] => + array (1) { + ["field"] => + string(3) "foo" + } + ["function"] => + object(Closure)#%d (0) { + } + ["phpobject"] => + object(Foo)#%d (1) { + ["field"] => + string(3) "php" + } +} +--- JS var_dump of JS object ---- +object(Object)#%d (12) { + ["undefined"] => + NULL + ["null"] => + NULL + ["bool"] => + bool(true) + ["string"] => + string(6) "string" + ["uint"] => + int(1) + ["int"] => + int(-1) + ["number"] => + float(3.141593) + ["regexp"] => + regexp(/regexp/) + ["array"] => + array(3) { + [0] => + int(1) + [1] => + int(2) + [2] => + int(3) + } + ["object"] => + object(Object)#%d (1) { + ["field"] => + string(3) "foo" + } + ["function"] => + object(Closure)#%d { + function id(x) { return x; } + } + ["phpobject"] => + object(Foo)#%d (1) { + ["field"] => + string(3) "php" + } +} +--- PHP var_dump of JS object ---- +object(V8Object)#%d (12) { + ["undefined"]=> + NULL + ["null"]=> + NULL + ["bool"]=> + bool(true) + ["string"]=> + string(6) "string" + ["uint"]=> + int(1) + ["int"]=> + int(-1) + ["number"]=> + float(3.141592654) + ["regexp"]=> + object(V8Object)#%d (0) { + } + ["array"]=> + array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + } + ["object"]=> + object(V8Object)#%d (1) { + ["field"]=> + string(3) "foo" + } + ["function"]=> + object(V8Function)#%d (0) { + } + ["phpobject"]=> + object(Foo)#%d (1) { + ["field"]=> + string(3) "php" + } +} +===EOF=== diff --git a/v8js_methods.cc b/v8js_methods.cc index d866645..a734c5c 100644 --- a/v8js_methods.cc +++ b/v8js_methods.cc @@ -61,13 +61,43 @@ static void _php_v8js_dumper(v8::Local var, int level TSRMLS_DC) /* { php_printf("%*c", (level - 1) * 2, ' '); } - if (var->IsNull()) + if (var.IsEmpty()) + { + php_printf("\n"); + return; + } + if (var->IsNull() || var->IsUndefined() /* PHP compat */) { php_printf("NULL\n"); return; } + if (var->IsInt32()) + { + php_printf("int(%ld)\n", (long) var->IntegerValue()); + return; + } + if (var->IsUint32()) + { + php_printf("int(%lu)\n", (unsigned long) var->IntegerValue()); + return; + } + if (var->IsNumber()) + { + php_printf("float(%f)\n", var->NumberValue()); + return; + } + if (var->IsBoolean()) + { + php_printf("bool(%s)\n", var->BooleanValue() ? "true" : "false"); + return; + } - v8::String::Utf8Value str(var->ToDetailString()); + v8::TryCatch try_catch; /* object.toString() can throw an exception */ + v8::Local details = var->ToDetailString(); + if (try_catch.HasCaught()) { + details = V8JS_SYM(""); + } + v8::String::Utf8Value str(details); const char *valstr = ToCString(str); size_t valstr_len = (valstr) ? strlen(valstr) : 0; @@ -75,26 +105,15 @@ static void _php_v8js_dumper(v8::Local var, int level TSRMLS_DC) /* { { php_printf("string(%zu) \"%s\"\n", valstr_len, valstr); } - else if (var->IsBoolean()) - { - php_printf("bool(%s)\n", valstr); - } - else if (var->IsInt32() || var->IsUint32()) - { - php_printf("int(%s)\n", valstr); - } - else if (var->IsNumber()) - { - php_printf("float(%s)\n", valstr); - } else if (var->IsDate()) { + // fake the fields of a PHP DateTime php_printf("Date(%s)\n", valstr); } #if PHP_V8_API_VERSION >= 2003007 else if (var->IsRegExp()) { - php_printf("RegExp(%s)\n", valstr); + php_printf("regexp(%s)\n", valstr); } #endif else if (var->IsArray()) @@ -119,18 +138,25 @@ static void _php_v8js_dumper(v8::Local var, int level TSRMLS_DC) /* { { v8::Local object = v8::Local::Cast(var); V8JS_GET_CLASS_NAME(cname, object); + int hash = object->GetIdentityHash(); if (var->IsFunction()) { v8::String::Utf8Value csource(object->ToString()); - php_printf("object(%s)#%d {\n%*c%s\n", ToCString(cname), object->GetIdentityHash(), level * 2 + 2, ' ', ToCString(csource)); + php_printf("object(Closure)#%d {\n%*c%s\n", hash, level * 2 + 2, ' ', ToCString(csource)); } else { - v8::Local keys = object->GetPropertyNames(); + v8::Local keys = object->GetOwnPropertyNames(); uint32_t length = keys->Length(); - php_printf("object(%s)#%d (%d) {\n", ToCString(cname), object->GetIdentityHash(), length); + if (strcmp(ToCString(cname), "Array") == 0 || + strcmp(ToCString(cname), "V8Object") == 0) { + php_printf("array"); + } else { + php_printf("object(%s)#%d", ToCString(cname), hash); + } + php_printf(" (%d) {\n", length); for (unsigned i = 0; i < length; i++) { v8::Local key = keys->Get(i)->ToString();