
本文介绍如何在不依赖 Laravel 的情况下,用原生 PHP 实现类似 Blade 的 {{key}} 变量插值功能,并优雅处理嵌套数组(如 {{user.profile.name}}),通过递归扁平化与正则替换完成多层级键名映射。
本文介绍如何在不依赖 laravel 的情况下,用原生 php 实现类似 blade 的 `{{key}}` 变量插值功能,并优雅处理嵌套数组(如 `{{user.profile.name}}`),通过递归扁平化与正则替换完成多层级键名映射。
在构建轻量级模板系统或解析自定义标记时,常需将形如 {{var}} 或 {{config.db.host}} 的占位符,按数据数组动态替换为对应值。原生 preg_replace 不支持嵌套键访问(如 $data['config']['db']['host']),而直接传入多维数组会导致“Array to string conversion”错误。核心挑战在于:将多维数组结构映射为扁平化的点号/下划线路径键名,并确保替换逻辑安全、可扩展。
以下是一个健壮、可复用的解决方案:
✅ 步骤一:递归扁平化多维数组
使用 flat_array() 函数将嵌套数组转换为单层关联数组,键名采用下划线连接(如 'var3_var5' → 对应原 ['var3']['var5'])。注意:该函数需就地修改(&$array),且每次扁平一层后立即递归处理新生成的键,避免遗漏深层嵌套(如 ["var6" => ["last" => "world", "another" => ["wo" => "asfasfd"]]]):
function flat_array(&$array) {
foreach ($array as $key => $val) {
if (is_array($val)) {
foreach ($val as $k => $v) {
$array[$key . '_' . $k] = $v; // 生成扁平键:var3_var5
}
unset($array[$key]); // 移除原始嵌套键
flat_array($array); // 继续处理新键(含 var6_last、var6_another_wo 等)
break; // 防止 foreach 迭代被破坏,确保单次只处理一个嵌套层
}
}
}
✅ 步骤二:模板内容替换
对模板字符串执行批量正则替换。关键点:
- 正则模式
/{{(.*?)}}/更健壮(匹配任意非贪婪内容),优于硬编码键名; - 使用
preg_replace_callback替代array_map + preg_replace,避免键名顺序依赖与数组长度不一致风险; - 在回调中动态查找扁平化后的键值,未命中时可返回原占位符或抛出警告。
优化后的完整示例:
<?php function flat_array(&$array) {
foreach ($array as $key => $val) {
if (is_array($val)) {
foreach ($val as $k => $v) {
$array[$key . '_' . $k] = $v;
}
unset($array[$key]);
flat_array($array);
break;
}
}
}
$content = "hello {{var}} world {{var2}} of what {{var3_var5}}?";
$data = [
"var" => "hello",
"var2" => "world",
"var3" => ["var4" => "what", "var5" => "asdf", "var6" => ["last" => "world", "another" => ["wo" => "asfasfd"]]]
];
// 扁平化数据
flat_array($data);
// 安全替换:支持 {{key}} 和 {{missing}}(不报错)
$result = preg_replace_callback(
'/\{\{([^}]+)\}\}/',
function ($matches) use ($data) {
$key = trim($matches[1]);
return $data[$key] ?? $matches[0]; // 未找到则保留原占位符
},
$content
);
echo $result; // 输出:hello hello world world of what asdf?
?>
⚠️ 注意事项与增强建议
-
安全性:生产环境应过滤
{{ }}中的恶意表达式(如{{ $user->delete() }}),本方案仅适用于纯数据插值,不可用于执行代码; -
键名分隔符:当前用
_,若原始键名含下划线(如'user_name'),建议改用.并同步调整正则(如{{user.name}}),再配合array_key_exists()逐级解析; - 性能:对超大模板或高频调用场景,可预编译正则或缓存扁平化结果;
-
兼容性:Laravel Blade 支持
{{ $user->name }}、@if等语法,本方案仅为变量替换子集,复杂逻辑请选用成熟模板引擎。
此方法简洁、无外部依赖,是理解模板引擎底层原理的理想实践——从多维数据到扁平映射,再到精准文本置换,每一步都直击动态内容渲染的核心。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











