这是我的PHP代码:
metrics.png
我当然会收到警告
为foreach()提供了无效的参数...
因为<?php
function getItems($arg) {
$products = array();
$products[] = (object) array('id' => '0', 'title' => 'Product1');
$products[] = (object) array('id' => '1', 'title' => 'Product2');
return $products;
}
$jsonContent = '{"myKey":["loop", "getItems(\"Arg\")", "<div><h3>{$item->title}</h3></div>"]}';
$jsonObj = json_decode($jsonContent);
$options = $jsonObj->myKey;
if($options[0] == 'loop') {
$html = [];
foreach($options[1] as $item) {
$html[] = $options[2];
}
echo implode('', $html);
}
?>
的参数不是数组而是字符串。
那么如何将字符串转换为函数名称并调用该函数呢?
以及如何将foreach()
数组的第三个元素用作循环中动态数据的包装器(希望您能通过代码理解我)
我需要得到以下结果:
$options
答案 0 :(得分:1)
它的基本思想是跳过foreach并仅“运行它”并输入options [2]作为参数,但是由于字符串具有()
,因此必须用substr删除。
$html = [];
$html[] =substr($options[1],0,-2)($options[2]);
var_dump($html);
我看到你问过一种没有评估的不同方法。
您可以在函数的循环中使用str_replace。
因为创建字符串时未定义产品,所以“”不会使其与函数中的产品值一致。
但这会(我想)会为您提供所需的输出。
function getItems($item) {
$products = array();
$products[] = (object) array('id' => '0', 'title' => 'Product1');
$products[] = (object) array('id' => '1', 'title' => 'Product2');
$return = "";
foreach($products as $prod){
$return .= str_replace('$products->title',$prod->title, $item);
}
return $return;
}
$jsonContent = '{"myKey":["loop", "getItems()", "<div><h3>{$products->title}</h3></div>", "<div><h1>{$products->title}</h1></div>"]}';
$jsonObj = json_decode($jsonContent);
$options = $jsonObj->myKey;
if($options[0] == 'loop') {
$html = [];
$func = substr($options[1],0,-2);
foreach(array_slice($options,2) as $arg){
$html[] = $func($arg);
}
var_dump($html);
}
/*
array(2) {
[0]=>
string(60) "<div><h3>{Product1}</h3></div><div><h3>{Product2}</h3></div>"
[1]=>
string(60) "<div><h1>{Product1}</h1></div><div><h1>{Product2}</h1></div>"
}
*/
如果您无法更改函数中的代码,请在“前端”进行相同的处理。
function getItems() {
$products = array();
$products[] = (object) array('id' => '0', 'title' => 'Product1');
$products[] = (object) array('id' => '1', 'title' => 'Product2');
return $products;
}
$jsonContent = '{"myKey":["loop", "getItems()", "<div><h3>{$products->title}</h3></div>", "<div><h1>{$products->title}</h1></div>"]}';
$jsonObj = json_decode($jsonContent);
$options = $jsonObj->myKey;
if($options[0] == 'loop') {
$html = [];
$func = substr($options[1],0,-2);
$products = $func();
foreach(array_slice($options,2) as $arg){
foreach($products as $prod){
$html[] = str_replace('$products->title',$prod->title, $arg);
}
}
var_dump($html);
}
/*
array(4) {
[0]=>
string(30) "<div><h3>{Product1}</h3></div>"
[1]=>
string(30) "<div><h3>{Product2}</h3></div>"
[2]=>
string(30) "<div><h1>{Product1}</h1></div>"
[3]=>
string(30) "<div><h1>{Product2}</h1></div>"
}
*/
答案 1 :(得分:1)
由于在HTML中添加值的额外复杂性,我只能想到邪恶的eval
。但是对于其余部分,只需将函数名称与参数分开,然后将它们创建为JSON中的数组。然后可以使用Argument unpacking ...
运算符来传递它们。我修改了该函数以显示传入的参数如何工作。
在JSON中,我有
["Product", 3]
映射到
function getItems( $prefix, $start) {
所以把它们放在一起...
function getItems( $prefix, $start) {
$products = array();
$products[] = (object) array('id' => '0', 'title' => $prefix.$start);
$products[] = (object) array('id' => '1', 'title' => $prefix.($start+1));
return $products;
}
$jsonContent = '{"myKey":["loop", "getItems", ["Product", 3],
"<div><h3>{$item->title}</h3></div>"]}';
$jsonObj = json_decode($jsonContent);
$options = $jsonObj->myKey;
if($options[0] == 'loop') {
$html = [];
foreach($options[1](...$options[2]) as $item) {
$html[] = eval("return \"{$options[3]}\";");
}
echo implode('', $html);
}
返回
<div><h3>Product3</h3></div><div><h3>Product4</h3></div>
答案 2 :(得分:0)
要调用字符串作为函数,您需要从字符串中删除()
。
$jsonContent = '{"myKey":["loop", "getItems", "<div><h3>{$item->title}</h3></div>"]}';
然后,在您的foreach()
循环上,像这样在$options[0]
之后再次添加它们:
foreach( $options[1]() as $item) {
$html[] = $options[2];
}
答案 3 :(得分:0)
这很黑,使用eval
,对不可信的数据可能很危险,但是很有趣:
$arg = 'something';
if($options[0] == 'loop') {
$func = rtrim($options[1], '()');
foreach($func($arg) as $item) {
eval("echo \"{$options[2]}\";");
}
}
或者没有参数的稍微不同的方法:
if($options[0] == 'loop') {
eval("\$items = {$options[1]};");
foreach($items as $item) {
eval("echo \"{$options[2]}\";");
}
}
答案 4 :(得分:0)
使用call_user_func从字符串中调用函数,并且正如Andreas指出的那样,对函数和参数使用单独的数组位置
但是我想指出的是,这非常复杂,也许没有必要……还有其他方法可以使它变得不复杂吗?
编辑:
为什么您需要传递一个甚至不使用的arg?
function getItems($arg) {
$products = array();
$products[] = (object) array('id' => '0', 'title' => 'Product1');
$products[] = (object) array('id' => '1', 'title' => 'Product2');
return $products;
}
$jsonContent = '{"myKey":["loop", "getItems", "Arg1,Arg2", "<div><h3>{$item->title}</h3></div>"]}';
$jsonObj = json_decode($jsonContent);
$options = $jsonObj->myKey;
if($options[0] == 'loop') {
$html = [];
$args = explode(',', $options[2]);
foreach($args as $item) {
$html[] = call_user_func ($options[1], $item);
}
echo implode('', $html);
}
?>````
答案 5 :(得分:0)
我认为通过对JSON进行一些更改,这将更加可行。
首先,我认为如果options
是一个对象而不是一个数组,它将使代码更具可读性,但是如果您愿意,同样的方法也应该适用于数组。其次,我认为模板中使用的函数参数和任何对象属性应该是单独的选项,以避免使用eval()
。
{
"myKey": {
"type": "loop",
"function": "getItems",
"args": [
"Arg"
],
"template": "<div><h3>%s<\/h3><\/div>",
"properties": [
"title"
]
}
}
解码JSON后用于处理选项的代码:
if ($options->type == 'loop') {
$html = [];
foreach (($options->function)(...$options->args) as $item) {
$html[] = vsprintf($options->template, array_map(function ($property) use ($item) {
return $item->$property;
}, $options->properties));
}
echo implode('', $html);
}
如果JSON可能来自任何外部来源,我不建议使用此方法。即使没有eval
,这似乎也是让人们在您的系统上执行任意代码的好方法。即使您只是自己使用它,我认为还是要至少根据允许的函数列表来验证函数名称,这还是谨慎的做法。
选项数组而不是对象的代码:
JSON:
{"myKey":["loop","getItems",["Arg"],"<div><h3>%s<\/h3><\/div>",["title"]]}
PHP:
if ($options[0] == 'loop') {
$html = [];
foreach (($options[1])(...$options[2]) as $item) {
$html[] = vsprintf($options[3], array_map(function ($property) use ($item) {
return $item->$property;
}, $options[4]));
}
echo implode('', $html);
}