Как мне вернуть буквальные значения строки PHP, чтобы она работала как код?

Я не уверен, что использую правильные термины даже здесь, но я попытаюсь объяснить. Я использую функцию PHP array_filter для фильтрации продуктов, и она вызывает вернуться к пользовательской функции, которую я создал, где я добавляю фильтры. Я могу очень легко сделать это жестко запрограммированным, но я, очевидно, хочу, чтобы он был динамичным:

Короче говоря, функция настраиваемого фильтра возвращается к функции array_filter () следующим образом:

return ($arr['colour']=='Red' || $arr['colour']=='White');

Это отлично работает, если жестко запрограммировано, как указано выше, и фильтрует массив, как и ожидалось, чтобы отображать только товары красного или белого цвета. Однако мне нужно, чтобы это было динамично.

Итак, как я могу построить строку значений, а затем использовать ее в операторе возврата?

Например:

$var = "$arr['colour'] == 'Red' || $arr['colour'] == 'White'";
return ($var);

Это не работает. Я пробовал использовать eval () (все равно не хочу!), Но все равно не сработало.

У меня есть следующий цикл построения строки из массива:

// $value=array of filters e.g colour=Black, colour=Red

$filterparts = explode("=", $value);

$filters[] = '$arr[\'' . $filterparts[0] . '\'] == \'' . $filterparts[1] . '\'';
// Creates array e.g $arr['colour'] = 'Red'

$imploded_filter = implode(" || ", $uniquefilters);
// Creates string, e.g. $arr['colour'] = 'Red' || $arr['colour'] = 'White'

Итак, если я повторю $ imploded_filter, я получу строку извлечения, которую хочу вернуть:

echo $imploded_filter;
// Outputs $arr['colour'] = 'Red' || $arr['colour'] = 'White'

Однако если я это сделаю

return($imploded_filter);

очевидно, что строка не оценивается как жесткий код, так что я могу сделать? Нужно ли мне что-то делать со строкой или возвращать ее другим способом, или создавать код, который мне нужно вернуть, совершенно другим способом?


person BenM    schedule 30.06.2016    source источник


Ответы (3)


Ключи массива можно указывать динамически. В eval() нет необходимости:

$value = $array[$key];

Вы можете создать список фильтров и сопоставить каждый из них в обратном вызове array_filter():

$filters = array(
    array('colour', array('white', 'blue')), // Multiple accepted values (OR)
    array('material', 'Fine Bone China'), // Single accepted value
);

$filtered = array_filter($products, function ($item) use ($filters) {
    // Match all filters
    foreach ($filters as $filter) {
        // Detect multi-value filter
        $isArrayFilter = is_array($filter[1]);

        if (
            // Check if multi-value filter doesn't match
            $isArrayFilter && !in_array($item[$filter[0]], $filter[1])
            // Check if a single-value filter doesn't match
            || !$isArrayFilter && $item[$filter[0]] != $filter[1]
        ) {
            // Filter doesn't match - exclude the item
            return false;
        }
    }

    // All filters match - include the item
    return true;
});
person ShiraNai7    schedule 30.06.2016
comment
Спасибо, похоже, это хорошо выполняет свою работу, выходит ли это за рамки этого вопроса (или даже функции array_filter!), Чтобы спросить, можно ли с ним работать, чтобы его ИЛИ для всех значений в категории (например, цвета), а затем И объединить его с другими категориями? - person BenM; 30.06.2016
comment
Например, цвет = красный || цвет = синий И материал = металл || material = paper ... на данный момент он просто проверяет, существует ли ЛЮБОЙ из них, и это нормально, но было бы неплохо добавить к нему эту функцию. - person BenM; 30.06.2016
comment
Вы можете поддерживать значения массива в $filterparts[1] ($filter[1]). Если это массив, вы сопоставляете его с in_array($arr[$filter[0]], $filter[1]), а не просто сравниваете. - person ShiraNai7; 30.06.2016
comment
Привет, мне очень жаль, но не могли бы вы сделать это для меня, пожалуйста, или приведите мне пример, мой мозг сегодня измотан, лол. скажем, у меня был массив цвет = красный, цвет = синий, материал = дерево, как все цвета могут быть сопоставлены как ИЛИ, а затем сказать И материал = дерево, поэтому ему нужно будет отфильтровать все красные ИЛИ синие продукты, которые сделаны из дерева - person BenM; 30.06.2016
comment
1) синтаксический анализ фильтров, чтобы каждый фильтр имел следующую структуру: ['property', 'value'] или ['property', ['value1', 'value2']] (если указано несколько значений) 2) поддерживать значения фильтра массива в обратном вызове array_filter() следующим образом: if (is_array($filter[1]) && in_array($arr[$filter[0]], $filter[1]) || !is_array($filter[1]) && $arr[$filter[0]] == $filter[1]) { - person ShiraNai7; 30.06.2016
comment
привет @ ShiraNai7, по какой-то причине он не дает ожидаемого результата, я установил фильтры следующим образом: $ filters = array (array ('color', array (white, blue)), array ('material', 'Fine Bone China ')); и обратный вызов, как вы указали в комментарии выше: - person BenM; 30.06.2016
comment
$ filter = array_filter ($ products, function ($ arr) use ($ filters) {// попытаться сопоставить все фильтры foreach ($ filters as $ filter) {if (is_array ($ filter [1]) && in_array ($ arr) [$ filter [0]], $ filter [1]) ||! is_array ($ filter [1]) && $ arr [$ filter [0]] == $ filter [1]) {// фильтр соответствует возврату true;}} // ни один фильтр не подошел return false;}); - person BenM; 30.06.2016
comment
он возвращает 6 результатов (есть 6 продуктов из костяного фарфора) независимо от того, что я выбираю в цветовой части, тогда как он должен показывать только 2 продукта (1 продукт из белого костяного фарфора, 1 продукт из синего костяного фарфора), если он работал так, как я хотел это к? Любые идеи? - person BenM; 30.06.2016
comment
Я обновил ответ новым кодом. (Вы не использовали обратный вызов фильтра, которого я ожидал.) - person ShiraNai7; 30.06.2016
comment
спасибо @ ShiraNai7, но если я заменю код приведенным выше на странице только белыми экранами, я не смогу найти полезную ошибку, но дальше по странице есть предупреждение ниже, заменив код обратно на более старый код, и страница отобразится и эта ошибка идет, любые идеи ?? Предупреждение: mysql_fetch_assoc () ожидает, что параметр 1 будет ресурсом с заданным логическим значением - person BenM; 30.06.2016
comment
PS Я удалил из второго массива в массиве фильтров, но это не помогло (но я все равно не думаю, что запятая должна быть в конце второго массива? - person BenM; 30.06.2016
comment
если я поменяю местами истину и ложь в возвратах, страница по крайней мере загружается, это как если бы она соответствовала своей просто возвращающей истине, а не отфильтрованному массиву или чему-то еще ?? - person BenM; 30.06.2016
comment
Проверьте свою версию PHP. Опубликованный мной код должен работать с PHP 5.3 или новее. Я передал фильтру некоторые тестовые данные, и он работает нормально. Выбросьте код из предыдущих комментариев. - person ShiraNai7; 30.06.2016
comment
Привет, я использую PHP 5.4, я только что понял, что это так же просто, как строчные имена цветов в списке фильтров ... вау, у меня один из тех дней, большое спасибо за вашу помощь с этим, если я мог бы проголосовать более одного раза, я бы! - person BenM; 30.06.2016

$colors = ['Red', 'White'];
$products = array_filter($products, function ($product) use ($colors) {
    return in_array($product['color'], $colors);
});

Практически никогда не возникает необходимости или необходимости «динамически создавать исходный код PHP». Всегда есть операция, которая может делать то, что вы хотите, с любым количеством элементов без необходимости объединения операторов ||. Здесь in_array - прекрасная функция для проверки одного значения против множества. Вы можете передавать массив цветов динамически, используя use ($colors).

Самый разумный обходной путь для старых версий PHP - аппроксимировать анонимный обратный вызов с помощью класса:

class InArrayFilterCallback {

    public $data = array();
    public $key;

    public __construct($data, $key) {
        $this->data = $data;
        $this->key = $key;
    }

    public callback($item) {
        return in_array($item[$this->key], $this->data);
    }

}

$products = array_filter($products, array(new InArrayFilterCallback($colors, 'color'), 'callback'));

Конечно, вы также можете использовать простой цикл foreach ...

person deceze♦    schedule 30.06.2016
comment
Привет и спасибо @deceze, знаете ли вы, работает ли это на PHP ‹5.5? Я получаю много ошибок, пытаясь использовать этот код :( - person BenM; 30.06.2016
comment
Это работает с версии 5.3, так как были введены анонимные функции. Для даже более старых версий (которые сейчас явно устарели !!) существует множество возможных обходных путей. Какую версию нужно поддерживать? - person deceze♦; 30.06.2016
comment
Привет, я использую 5.4, но не могу заставить ни один из них работать: / обходной путь просто белые экраны и по какой-то причине даже не выдает ошибку (!) - person BenM; 30.06.2016
comment
Хорошо, я такой тупой, я не видел американского цветового написания, когда в моем массиве он цвет ... теперь все работает, я думаю, просто нужно еще немного поработать! - person BenM; 30.06.2016
comment
Итак, возвращаясь к исходной проблеме создания этой динамики, как бы мне преобразовать ваше решение, чтобы разрешить ему передавать цвет, материал и т. Д., На данный момент у вас есть такие вещи, как $ product ['color'], $ colors жестко запрограммированы, тогда как у меня есть массив значений, таких как материал = металл, цвет = черный и т. д., и т. д. Мне нужно динамически передавать фильтру? - person BenM; 30.06.2016
comment
Насколько это должно быть динамично? Поскольку это крошечный однострочник для написания, может иметь гораздо больше смысла иметь кучу этих array_filter вызовов подряд, каждый из которых фильтрует что-то еще. Кроме того, вы уже передаете $colors динамически, вы также можете передать ключ для динамической проверки, а затем использовать цикл. И последнее, но не менее важное: другие ответы здесь показывают вам, как создать кучу условий фильтрации и проверить их в рамках одного обратного вызова фильтра. - person deceze♦; 30.06.2016
comment
Спасибо, я действительно ценю это, я проголосовал за, но принял ответ ниже, так как это тоже происходило динамически, еще раз спасибо за вашу помощь! - person BenM; 30.06.2016

Используйте функцию in_array, например:

$filters = [
    'colour' => [
        'red',
        'blue',
    ]
];
array_filter($list, function ($item) use ($filters) {
    foreach ($filters as $index => $filter) {
        if (!in_array($item[$index], $filter)) {
            return false;
        }
    }
    return true;
});

Создавать строку и вычислять ее - никогда не лучшая идея.

person hooman naghiee    schedule 30.06.2016