Рекомендации на будущее с системой голосования. Как пропустить необязательные аргументы в вызове функции? Значение, возвращаемое функцией

invalid argument (16)

Мне часто приходится обрабатывать данные, которые могут быть либо массивом, либо нулевой переменной, и передавать некоторые данные для этих данных.

$values = get_values(); foreach ($values as $value){ ... }

Когда вы кормите foreach данными, которые не являются массивом, вы получаете предупреждение:

Предупреждение: неверный аргумент, предоставленный foreach () в [...]

Предполагая, что невозможно get_values() функцию get_values() чтобы всегда возвращать массив (обратная совместимость, недоступный исходный код, по какой-либо другой причине), мне интересно, какой из них самый чистый и эффективный способ избежать этих предупреждений:

  • Вычисление $values массива
  • Инициализация $values для массива
  • Обертка foreach с if
  • Другое (пожалуйста, предлагайте)
Answers

Прежде всего, каждая переменная должна быть инициализирована. Всегда.
Кастинг не вариант.
если get_values ​​(); может возвращать переменную типа, это значение должно быть проверено, конечно.

Используйте функцию is_array, когда вы передадите массив в цикл foreach.

If (is_array($your_variable)) { foreach ($your_variable as $item) { //your code } }

Попробуй это:

//Force array $dataArr = is_array($dataArr) ? $dataArr: array($dataArr); foreach ($dataArr as $val) { echo $val; }

$values = get_values(); foreach ((array) $values as $value){ ... }

Проблема всегда равна нулю, а литье - это чистое решение.

Если вы используете php7 и хотите обрабатывать только неопределенные ошибки, это самый чистый IMHO

$array = ; foreach ($array ?? as $item) { echo $item; }

Я буду использовать комбинацию пустых, isset и is_array как

$array = ["dog", "cat", "lion"]; if(!empty($array) && isset($array) && is_array($array){ //loop foreach ($array as $values) { echo $values; } }

Похоже, что есть отношение к окружающей среде:

У меня был «недопустимый аргумент, предоставленный foreach ()», ошибка только в среде dev, но не в prod (я работаю на сервере, а не на localhost).

Несмотря на ошибку, var_dump указал, что массив там хорошо (в обоих случаях - приложение и dev).

Значение if (is_array($array)) вокруг foreach ($array as $subarray) решило проблему.

Пожалуйста, не зависеть от кастинга как решения , хотя другие предлагают это как допустимый вариант для предотвращения ошибки, это может привести к другому.

Имейте в виду : если вы ожидаете вернуть определенную форму массива, это может не сработать. Для этого требуются дополнительные проверки.

Например, приведение boolean в массив (array)bool не приведет к пусту массива, а массив с одним элементом, содержащим логическое значение как int: или .

Я написал быстрый тест, чтобы представить эту проблему . (Вот тест резервного копирования, если первый тестовый URL-адрес не работает.)

Включены тесты для: null , false , true , class , array и undefined .

Всегда проверяйте свой ввод перед его использованием в foreach. Предложения:

  • Быстрая проверка типов : $array = is_array($var) or is_object($var) ? $var: ; $array = is_array($var) or is_object($var) ? $var: ;
  • Тип подсказки массивов в методах перед использованием foreach и указания типов возврата
  • Обертка foreach внутри if
  • Использование блоков try{}catch(){}
  • Разработка надлежащего кода / тестирования перед выпуском продукции
  • Чтобы проверить массив на правильную форму, вы можете использовать array_key_exists на определенном ключе или проверить глубину массива (когда он один!) .
  • Всегда извлекайте свои вспомогательные методы в глобальное пространство имен, чтобы уменьшить дубликат кода
  • я бы сделал то же самое, что и Энди, но использовал «пустую» функцию.

    If(empty($yourArray)) {echo"

    There"s nothing in the array.....

    ";} else { foreach ($yourArray as $current_array_item) { //do something with the current array item here } }

    Более сжатое расширение кода @ Kris

    Function secure_iterable($var) { return is_iterable($var) ? $var: array(); } foreach (secure_iterable($values) as $value) { //do stuff... }

    особенно для использования кода внутри шаблона

    ...

    Исключительный случай для этого уведомления возникает, если вы устанавливаете массив в null внутри цикла foreach

    If (is_array($values)) { foreach ($values as $value) { $values = null;//WARNING!!! } }

    Лично я считаю, что это самый чистый - не уверен, что это самый эффективный, ум!

    If (is_array($values) || is_object($values)) { foreach ($values as $value) { ... } }

    Причина моего предпочтения заключается в том, что он не выделяет пустой массив, когда вам вообще нечего начинать.

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

    Если вы не переносите свой сайт, и это просто проблема, возникшая при попытке обновления до PHP 5. Это позаботится о некоторых из этих проблем. Может показаться глупым решением, но сделал трюк для меня.

    Будучи укушенным этим, у меня есть привычка включать локально определенные переменные в самый внутренний объем, который я использую для передачи на любое закрытие. В вашем примере:

    Foreach (var s in strings) { query = query.Where(i => i.Prop == s); // access to modified closure

    Foreach (var s in strings) { string search = s; query = query.Where(i => i.Prop == search); // New definition ensures unique per iteration.

    Как только у вас есть эта привычка, вы можете избежать этого в очень редком случае, когда вы намеревались привязываться к внешним областям. Честно говоря, я не думаю, что когда-либо делал это.

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

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

    XHTML

    Используем новый тип документа HTML5, определяем секцию head, вставляем тег title , основную таблицу стилей - styles.css .

    demo.php Рекомендации на будущее (используем PHP, jQuery и MySQL) | сайт have_voted ? "inactive" : "active").""> ".$this->suggestion." ".(int)$this->rating." "; } }

    Метод __toString() используется для создания представления объекта в виде строки. Таким образом мы можем построить разметку HTML, включая заголовок предложения и количество голосов.

    Метод __get() используется для предоставления доступа к неопределённым свойствам класса для массива $data . Это означает, что если мы хотим получить доступ к $obj->suggestion , а данное свойство не определено, то оно будет получено из массива $data и возвращено так, как будто оно существует. Таким образом мы можем передать массив конструктору, вместо того, чтобы устанавливать все свойства. Мы используем такой подход, когда создаем объект в ajax.php .

    Теперь перейдем к генерированию неупорядоченного списка для страницы.

    demo.php require "connect.php"; require "suggestion.class.php"; // Конвертируем IP в число. Это более эффективный способ хранения IP // в базе данных: $ip = sprintf("%u",ip2long($_SERVER["REMOTE_ADDR"])); // Следующий запрос использует left join для выбора // всех предложений и одновременно определяет, // голосовал ли пользователь за них. $result = $mysqli->query(" SELECT s.*, if (v.ip IS NULL,0,1) AS have_voted FROM suggestions AS s LEFT JOIN suggestions_votes AS v ON(s.id = v.suggestion_id AND v.day = CURRENT_DATE AND v.ip = $ip) ORDER BY s.rating DESC, s.id DESC "); $str = ""; if(!$mysqli->error) { // Генерируем UL $str = "
      "; // Используем метод MySQL fetch_object для создания нового объекта // и наполнения его столбцами результата запроса: while($suggestion = $result->fetch_object("Suggestion")){ $str.= $suggestion; // Используем метод __toString(). } $str .="
    "; }

    После выполнения запроса мы используем метод fetch_object() объекта $result . Данный метод создает объект заданного класса для каждой строки результата запроса, и назначает столбцы каждой строчки как публичные свойства объекта.

    PHP также управляет запросами AJAX, отправляемыми jQuery. Это реализовано в ajax.php . Для разделения действий AJAX, скрипт использует параметр $_GET["action"] , который может иметь одно из двух значений - ‘vote ‘ или ‘submit ‘.

    ajax.php require "connect.php"; require "suggestion.class.php"; // если запрос пришел не от AJAX, то выходим: if($_SERVER["HTTP_X_REQUESTED_WITH"] !="XMLHttpRequest"){ exit; } // Конвертируем IP в число. Это более эффективный способ хранения IP в базе данных: $ip = sprintf("%u",ip2long($_SERVER["REMOTE_ADDR"])); if($_GET["action"] == "vote"){ $v = (int)$_GET["vote"]; $id = (int)$_GET["id"]; if($v != -1 && $v != 1){ exit; } // Проверяем, существует ли такой id предложения: if(!$mysqli->query("SELECT 1 FROM suggestions WHERE id = $id")->num_rows){ exit; } // Поля id, ip и day является основным ключем. // Запрос потерпит неудачу, если мы будем пытаться вставить дупликат ключа, // что означает возможность для пользователя голосовать только один раз в день. $mysqli->query(" INSERT INTO suggestions_votes (suggestion_id,ip,day,vote) VALUES ($id, $ip, CURRENT_DATE, $v) "); if($mysqli->affected_rows == 1) { $mysqli->query(" UPDATE suggestions SET ".($v == 1 ? "votes_up = votes_up + 1" : "votes_down = votes_down + 1").", rating = rating + $v WHERE id = $id "); } } else if($_GET["action"] == "submit"){ if(get_magic_quotes_gpc()){ array_walk_recursive($_GET,create_function("&$v,$k","$v = stripslashes($v);")); } // Зачищаем контент $_GET["content"] = htmlspecialchars(strip_tags($_GET["content"])); if(mb_strlen($_GET["content"],"utf-8")query("INSERT INTO suggestions SET suggestion = "".$mysqli->real_escape_string($_GET["content"])."""); // Вывод HTML кода нового созданного предложения в формате JSON. // Мы используем (string) для вызова магического метода __toString(). echo json_encode(array("html" => (string)(new Suggestion(array("id" => $mysqli->insert_id, "suggestion" => $_GET["content"]))))); }

    Когда jQuery отправляет запрос ‘vote ‘, не предполагается никакого возвращаемого значения, таким образом скрипт ничего не выводит. При запросе ‘submit ‘, jQuery ожидает возвращения объекта JSON, который содержит разметку HTML для предложения, которое только-что было вставлено. Именно здесь создается новый объект Suggestion с использованием магического метода __toString() и конвертированием с помощью функции json_encode() .

    jQuery

    Весь код jQuery располагается в файле script.js . Он отслеживает события нажатия кнопки мыши для красной и зеленой стрелочек. Но так как предложение может быть вставлено в любой момент, то используется метод jQuery live() .

    script.js $(document).ready(function(){ var ul = $("ul.suggestions"); // Отслеживаем нажатие на стрелочках ВВЕРХ или ВНИЗ: $("div.vote span").live("click",function(){ var elem = $(this), parent = elem.parent(), li = elem.closest("li"), ratingDiv = li.find(".rating"), id = li.attr("id").replace("s",""), v = 1; // Если пользователь уже голосовал: if(parent.hasClass("inactive")){ return false; } parent.removeClass("active").addClass("inactive"); if(elem.hasClass("down")){ v = -1; } // Увеличиваем счетчик справа: ratingDiv.text(v + +ratingDiv.text()); // Помещаем все элементы LI в массив // и сортируем его по количеству голосов: var arr = $.makeArray(ul.find("li")).sort(function(l,r){ return +$(".rating",r).text() - +$(".rating",l).text(); }); // Добавляем отсортированные элементы LI в UL ul.html(arr); // Отправляем запрос AJAX $.get("ajax.php",{action:"vote",vote:v,"id":id}); }); $("#suggest").submit(function(){ var form = $(this), textField = $("#suggestionText"); // Предотвращение дублирования запросов: if(form.hasClass("working") || textField.val().length

    Если необходимо разрешить функции изменять переданные аргументы за ее пределами, вы должны передавать их по ссылке. Для того, чтобы аргумент был передан по ссылке, необходимо указать знак & (амперсанд) перед именем параметра в определении функции:

    Функции могут определять значения аргументов по умолчанию. Чтобы установить значение по умолчанию, в определении функции нужно всего лишь присвоить параметру желаемое значение:

    Примечание: все параметры, для которых установлены значения аргументов по умолчанию, должны находиться правее аргументов, для которых значения по умолчанию не заданы, так как в противном случае ваш код может работать не так, как вы того ожидали:

    Значение, возвращаемое функцией

    Когда выполнение функции завершается, она может возвратить некоторое значение (результат работы функции) программе, которая её вызвала. Оператор return внутри функций служит для определения значения, возвращаемого функцией. В качестве возвращаемого значения может быть любой тип. Он имеет следующий синтаксис:

    Return выражение;

    Оператор return может быть расположен в любом месте функции. Когда до него доходит управление, функция возвращает значение (если указано) и завершает свое выполнение. Если оператор return не указан или не указано возвращаемое значение, то функция вернет значение NULL . Для использования возвращаемого значения, результат выполнения функции можно присвоить к примеру переменной: