// Exports the given xml key value pair as an xml child of the given parent node static void xdebug_array_element_export_xml_node(xdebug_xml_node& parent, const char* parentName, const Variant& key, const Variant& val, XDebugExporter& exporter) { String key_str = key.toString(); Variant full_name = init_null(); // Construct the full name StringBuffer buf; if (parentName != nullptr) { if (key.isInteger()) { buf.printf("%s[%s]", parentName, key_str.data()); } else { buf.printf("%s['%s']", parentName, key_str.data()); } full_name = buf.detach(); } const char* full_name_str = full_name.isNull() ? nullptr : full_name.toString().data(); // Recursively add the child xdebug_xml_node* child = xdebug_var_export_xml_node(xdstrdup(key_str.data()), xdstrdup(full_name_str), nullptr, val, exporter); xdebug_xml_add_child(&parent, child); }
xdebug_xml_node* xdebug_get_value_xml_node(const char* name, const Variant& val, XDebugVarType type /* = XDebugVarType::Normal */, XDebugExporter& exporter) { // Compute the short and full name of the passed value char* short_name = nullptr; char* full_name = nullptr; if (name) { switch (type) { case XDebugVarType::Normal: { char* tmp_name = prepare_variable_name(name); short_name = xdstrdup(tmp_name); full_name = xdstrdup(tmp_name); xdfree(tmp_name); break; } case XDebugVarType::Static: short_name = xdebug_sprintf("::%s", name); full_name = xdebug_sprintf("::%s", name); break; case XDebugVarType::Constant: short_name = xdstrdup(name); full_name = xdstrdup(name); break; default: throw Exception("Invalid variable type"); } } // Recursively construct the xml return xdebug_var_export_xml_node(short_name, full_name, nullptr, val, exporter); }
static void xdebug_object_element_export_xml_node(xdebug_xml_node& parent, const char* parentName, const ObjectData* obj, const Variant& key, const Variant& val, XDebugExporter& exporter) { auto const prop_str = key.toString(); auto const cls = obj->getVMClass(); auto const cls_name = cls->name()->data(); // Compute whether the properity is static. auto const sLookup = cls->getSProp(nullptr, prop_str.get()); auto const is_static = sLookup.prop != nullptr; bool visible = is_static; bool accessible = sLookup.accessible; // If the property is not static, we know it's a member, but need to grab the // visibility if (!is_static) { bool unset; obj->getProp(nullptr, prop_str.get(), visible, accessible, unset); } // This is public if it is visible and accessible from the nullptr context bool is_public = visible && accessible; // Compute the property name and full name const char* name; const char* full_name = nullptr; if (!val.isInteger()) { // Compute the property name if (is_public) { name = xdstrdup(prop_str.data()); } else { name = xdebug_sprintf("*%s*%s", cls_name, prop_str.data()); } // Compute the property full name if we have a parent name if (parentName != nullptr) { if (is_public && is_static) { full_name = xdebug_sprintf("%s::%s", parentName, prop_str.data()); } else if (is_public && !is_static) { full_name = xdebug_sprintf("%s->%s", parentName, prop_str.data()); } else if (!is_public && is_static) { full_name = xdebug_sprintf("%s::*%s*%s", parentName, "::", cls_name, prop_str.data()); } else if (!is_public && !is_static) { full_name = xdebug_sprintf("%s->*%s*%s", parentName, "->", cls_name, prop_str.data()); } } } else { // Compute the name + full name if we have a parent name name = xdebug_sprintf("%ld", key.toInt64()); if (parentName != nullptr) { if (is_static) { full_name = xdebug_sprintf("%s::%ld", parentName, key.toInt64()); } else { full_name = xdebug_sprintf("%s->%ld", parentName, key.toInt64()); } } } // Compute the facet (static/non-static + public/private) const char* facet = xdebug_sprintf("%s%s", is_static ? "static " : "", is_public ? "public" : "private"); // Recursively write the this property. The duplications are necessary due to // the xdebug xml api xdebug_xml_node* child = xdebug_var_export_xml_node(xdstrdup(name), xdstrdup(full_name), xdstrdup(facet), val, exporter); xdebug_xml_add_child(&parent, child); }