in hphp/runtime/base/variable-serializer.cpp [837:1088]
void VariableSerializer::writeArrayHeader(int size, bool isVectorData,
VariableSerializer::ArrayKind kind) {
m_arrayInfos.push_back(ArrayInfo());
ArrayInfo &info = m_arrayInfos.back();
info.first_element = true;
info.indent_delta = 0;
info.size = size;
switch (m_type) {
case Type::DebuggerDump:
case Type::PrintR:
if (!m_rsrcName.empty()) {
m_buf->append("Resource id #");
m_buf->append(m_rsrcId);
if (m_type == Type::DebuggerDump) {
m_buf->append(" of type ");
m_buf->append(m_rsrcName);
}
break;
} else if (!m_objClass.empty()) {
m_buf->append(m_objClass);
m_buf->append(" Object\n");
} else {
switch (kind) {
case ArrayKind::Dict:
m_buf->append("Dict\n");
break;
case ArrayKind::Vec:
m_buf->append("Vec\n");
break;
case ArrayKind::Keyset:
m_buf->append("Keyset\n");
break;
case ArrayKind::PHP:
case ArrayKind::VArray:
case ArrayKind::DArray:
case ArrayKind::MarkedVArray:
case ArrayKind::MarkedDArray:
m_buf->append("Array\n");
break;
}
}
if (m_indent > 0) {
m_indent += 4;
indent();
}
m_buf->append("(\n");
m_indent += (info.indent_delta = 4);
break;
case Type::VarExport:
case Type::PHPOutput:
if (m_indent > 0 && m_rsrcName.empty() && m_keyPrinted) {
m_buf->append('\n');
indent();
}
if (!m_objClass.empty()) {
m_buf->append(m_objClass);
if (m_objCode == 'O') {
m_buf->append("::__set_state(darray[\n");
} else {
assertx(m_objCode == 'V' || m_objCode == 'K');
m_buf->append(" {\n");
}
} else if (!m_rsrcName.empty()) {
m_buf->append("NULL");
} else {
switch (kind) {
case ArrayKind::Dict:
m_buf->append("dict [\n");
break;
case ArrayKind::Vec:
m_buf->append("vec [\n");
break;
case ArrayKind::Keyset:
m_buf->append("keyset [\n");
break;
case ArrayKind::PHP:
m_buf->append("array (\n");
break;
case ArrayKind::VArray: {
auto const dvarray = RO::EvalHackArrDVArrVarExport ||
m_type == Type::PHPOutput;
m_buf->append(dvarray ? "varray [\n" : "array (\n");
break;
}
case ArrayKind::DArray: {
auto const dvarray = RO::EvalHackArrDVArrVarExport ||
m_type == Type::PHPOutput;
m_buf->append(dvarray ? "darray [\n" : "array (\n");
break;
}
case ArrayKind::MarkedVArray:
case ArrayKind::MarkedDArray:
always_assert(0);
}
}
m_indent += (info.indent_delta = 2);
break;
case Type::VarDump:
case Type::DebugDump:
indent();
if (!m_rsrcName.empty()) {
m_buf->append("resource(");
m_buf->append(m_rsrcId);
m_buf->append(") of type (");
m_buf->append(m_rsrcName);
m_buf->append(")\n");
break;
} else if (!m_objClass.empty()) {
m_buf->append("object(");
m_buf->append(m_objClass);
m_buf->append(") ");
} else {
auto const header = [&]() {
switch (kind) {
case ArrayKind::Dict:
return "dict";
case ArrayKind::Vec:
return "vec";
case ArrayKind::Keyset:
return "keyset";
case ArrayKind::PHP:
return "array";
case ArrayKind::VArray:
case ArrayKind::MarkedVArray:
return "varray";
case ArrayKind::DArray:
case ArrayKind::MarkedDArray:
return "darray";
}
not_reached();
}();
m_buf->append(header);
}
m_buf->append('(');
m_buf->append(size);
m_buf->append(')');
// ...so to strictly follow PHP's output
if (m_type == Type::VarDump) {
m_buf->append(' ');
} else {
writeRefCount();
}
m_buf->append("{\n");
m_indent += (info.indent_delta = 2);
break;
case Type::Serialize:
case Type::Internal:
case Type::APCSerialize:
case Type::DebuggerSerialize:
if (!m_rsrcName.empty() && m_type == Type::DebuggerSerialize) {
m_buf->append("L:");
m_buf->append(m_rsrcId);
m_buf->append(":");
m_buf->append((int)m_rsrcName.size());
m_buf->append(":\"");
m_buf->append(m_rsrcName);
m_buf->append("\"{");
} else if (!m_objClass.empty()) {
m_buf->append(m_objCode);
m_buf->append(":");
m_buf->append((int)m_objClass.size());
m_buf->append(":\"");
m_buf->append(m_objClass);
m_buf->append("\":");
m_buf->append(size);
m_buf->append(":{");
} else {
switch (kind) {
case ArrayKind::Dict:
m_buf->append("D:");
break;
case ArrayKind::Vec:
m_buf->append("v:");
break;
case ArrayKind::MarkedVArray:
m_buf->append("x:");
break;
case ArrayKind::MarkedDArray:
m_buf->append("X:");
break;
case ArrayKind::Keyset:
m_buf->append("k:");
break;
case ArrayKind::PHP:
m_buf->append("a:");
break;
case ArrayKind::VArray:
m_buf->append("y:");
break;
case ArrayKind::DArray:
m_buf->append("Y:");
break;
}
m_buf->append(size);
m_buf->append(":{");
}
break;
case Type::JSON:
info.is_vector =
(m_objClass.empty() || m_objCode == 'V' || m_objCode == 'K') &&
isVectorData &&
kind != ArrayKind::Dict;
if (info.is_vector && m_type == Type::JSON) {
info.is_vector = (m_option & k_JSON_FORCE_OBJECT)
? false : info.is_vector;
}
if (info.is_vector || kind == ArrayKind::Keyset) {
if (UNLIKELY(RuntimeOption::EvalHackArrCompatSerializeNotices) &&
kind == ArrayKind::DArray) {
if (size == 0 && m_edWarn && !m_hasEDWarned) {
raise_hackarr_compat_notice("JSON encoding empty darray");
m_hasEDWarned = true;
} else if (size != 0 && m_vdWarn && !m_hasVDWarned) {
raise_hackarr_compat_notice("JSON encoding vec-like darray");
m_hasVDWarned = true;
}
}
m_buf->append('[');
} else {
if (UNLIKELY(RuntimeOption::EvalHackArrCompatSerializeNotices) &&
kind == ArrayKind::DArray && m_ddWarn && !m_hasDDWarned) {
raise_hackarr_compat_notice("JSON encoding dict-like darray");
m_hasDDWarned = true;
}
m_buf->append('{');
}
if (m_type == Type::JSON && (m_option & k_JSON_PRETTY_PRINT) &&
info.size > 0) {
m_buf->append("\n");
m_indent += (info.indent_delta = 4);
}
break;
default:
assertx(false);
break;
}
// ...so we don't mess up next array output
if (!m_objClass.empty() || !m_rsrcName.empty()) {
m_objClass.clear();
info.is_object = true;
} else {
info.is_object = false;
}
}