Pull to refresh

Comments 56

У меня есть один вопрос к разработчикам на php. Ребята, объясните мне, почему вы называете словарь (отображение ключей на значения) массивом? Этот вопрос терзает меня уже долгие годы и я никак не найду на него ответ. В том же пайтоне, эти вещи честно называются словарями, списками и т.д. И это единственный язык, в процессе изучения которого, я не понимал, почему тернарный вопросик возвращает мне не то, что нужно. Ах да, потому, что он тут работает с заду на перед.

И это, наверное, единственный язык, который при выходе за пределы так называемого массива создает недостающий элемент и воспринимает его как null тем самым завершая цикл.

Да, прошу прощения, накипело.
Не ради троллинга php, но мне тоже интересно почему было принято такое решение. Думаю для этого были какие-то причины.
Если вы про тернарный оператор, то вот здесь есть обсуждение.
Я вот и не подозревал о том, что такое может случиться, просто потому что привык для собственного удобства чтения везде ставить скобки.
Трудно, наверное, когда название чего-то приносит страдания долгие годы.
Что же они творят-то, бесстыдники-создатели php!
Потому что в PHP «массив» является одновременно массивом и упорядоченным словарем. Позволяет не плодить лишних сущностей. По-моему, это очень удобная фишка, которую другие языки (тот же JS) не поддерживают.

Сам термин «массив», наверное, не слишком точный, но тут уж ничего не поделаешь, таков PHP ;).
Я думаю, потому, что для его создания используется ключевое слово array. Хотя согласен, это не массив в привычном понимании.
А что не устраивает собственно в названии «массив»?)
Все структуры, которые Вы перечислили имеют одну общую черту: «упорядоченное отображение, которое устанавливает соответствие между значением и ключом», почему бы не назвать все это одним словом по самой элементарной структуре данных — «Массив»?)

И, кстати, зря Вы упомянули пайтон, потому что я ни разу не встречал человека, который знает все встроенные типы данных(http://docs.python.org/2/library/datatypes.html), а вот любой программист PHP прекрасно их знает(http://php.net/manual/ru/language.types.php).
UFO just landed and posted this here
«Встроенные» — это __builtins__

>>> [item for item in dir(__builtins__)
...  if isinstance(getattr(__builtins__, item), type) and item.lower() == item]

['bool', 'bytearray', 'bytes', 'classmethod', 'complex', 'dict', 'enumerate', 'filter', 'float', 'frozenset', 'int', 'list', 'map', 'memoryview', 'object', 'property', 'range', 'reversed', 'set', 'slice', 'staticmethod', 'str', 'super', 'tuple', 'type', 'zip']
Ну тут часть — это функции преобразования. В том же php array_combine() не является типом, как zip().
Так что типов основных совсем мало.
Потому что в PHP и словари, и просто массивы заводятся с помощью ключевого слова array.
И обычный массив в PHP — это словарь, ключи, которого индексы.

И в словарь, который на самом деле словарь, можно сделать команду push в PHP.
foreach работает со всем, что поддерживает интерфейс Traversable: с массивами, с простыми объектами (где перечисляются доступные свойства) и с Traversable-объектами (вернее, объектами, у которых определен внутренний обработчик get_iterator)
Эта формулировка явно смущает, ведь ни массивы, ни простые объекты не поддерживают Traversable.
(Для проверки достаточно попробовать передать значение в iterator_to_array или применить instanceof.)
В оригинале это звучит так: "foreach works with all kinds of traversables".
Тут я, скорее всего, плохо перевел. Какую формулировку предложили бы вы?
В оригинале слово traversable используется в общем смыле. Перевести можно, например, так:
"foreach поддерживает значения разных типов, например, обычные массивы, обычные объекты, объекты, поддерживающие Traversable".

Меня оригинальная фраза тоже смущает, но по другой причине. В ней «разнообразные» применяется к набору всего лишь из двух: массивы и объекты.
Думаю, вы правы. Исправил в тексте, с небольшим изменением. Спасибо за корректировку.
Level up! Предупреждён — значит, вооружён.
Лично у меня в голове отложилось только одно: чтобы не попасть в непонятное, надо всеми силами избегать модифицирования обходимого через foreach массива. Но таки да, во всем этом видна определенная логика, о наличии которой я раньше и не подозревал.
Эмпирически выведенный закон «хочешь действительно понять фреймворк — читай не документацию, а его код» применим и к языкам программирования.
Мне лично вообще трудно себе представить задачу, в которой может понадобиться модифицировать массив при обходе.
Мне кажется, что в 90% случаев foreach используется для чтения данных из массива
почему, такие ситуации легко представить
хотя я бы в них использовал while

массив не меняется — foreach
меняется — while
В PHP — и правда, сложно представить. Но такие задачи часто встречаются, например, при написании игр. Простейший пример: по экрану разбросаны квадраты, при нажатии на любой он взрывается. Тогда у нас получится цикл по коллекции объектов на экране, каждая итерация которого проверяет нажатие для конкретного объекта, и если оно успешно — сам объект удаляется из коллекции, зато добавляются новые (спрайт взрыва и искры).
тогда у нас получится цикл по коллекции объектов на экране, каждая итерация которого проверяет нажатие для конкретного объекта, и если оно успешно

OMG! это еще хуже, чем изменять массивы в цикле на php. Для этого существуют эвенты у каждого объекта и их обработчики. Представьте, что у вас 100к таких объектов? Цикл по всем и перестройка? Да ну нафиг-нафиг.
Неправда. Вы когда-нибудь писали игры? Специфика такова, что одновременно на экране объектов довольно немного (у меня в среднем бывало от 50 до 500), и каждый из них нужно обновить и отрисовать со скоростью 50+ FPS. Система событий в таких условиях никакого выигрыша не даст.
Почему нельзя сделать это через for?
Дело в том, что с объектами удобнее работать, когда они не просто валяются в общем массиве, но сгруппированы. Сложный объект из нескольких составных частей, которые должны двигаться вместе, удобне представить в виде группы объектов, которая имеет общую точку, относительно которой позиционируются вложенные объекты. В таком случае у нас получается по вложенному циклу на каждый такой сгруппированный объект, и понять, какой индекс цикла нужно ручками подкрутить на единицу вверх или вниз, становится абсолютно невозможно.
В этом случае не стоило бы явно прописать итератор для объекта?
Я говорю о том, чтобы руками указать, в каком порядке и каким образом foreach следует обходить вашу коллекцию.

p.s. Хотя не вполне понимаю, что мы тут обсуждаем. Сдается мне, врядли вы собираетесь писать такого рода игру на PHP, так что как он пытается защитить итератор от перезаписи тут уже не так важно.
Ужас, психоделическая картина, коллизии, шизофрения. Опасно работать программистом!
Не ради холивара, но все-таки не могу не сказать, что в C# обход коллекций сделан куда более логично и понятно. Никаких «внутренних индексов массива» нет. На каждый обход последовательности создается специальный объект — итератор, который хранит в себе текущий индекс и удаляется после окончания обхода. Если последовательность была изменена во время обхода, итератор бросает исключение.
это легаси из предыдущих версий.внутренний итератор, который нужен для случаев, когда вы обходите массив при помощи методов next/prev/current/reset. соответственно несколько альтернативных методов обхода как-то должны были взаимодействовать :)
Простите, что не в тему, но уже неоднократно сталкиваюсь с проблемой count, когда нет массива(переменной) или он пустой отрабатывает на true. Может кто сталкивался, в чём подвох не могу понять, заранее спасибо.
В каком смысле true? Он же целое число возвращает. На пустой массив или на null он возвращает 0.
Прочтите внимательней документацию. count (array ()) = 0, count (false) = 1
Давно уже не объявлять переменные считает дурным стилем.
Добавление $arr = array(); во первых много времени не занимает, во вторых как способ принудительной типизации тоже неплохо
Может Вам empty подойдёт?
наверно потому что он конвертит не массив в массив с одним елементом а потом считает.
use count((array)$any_data)
:^ ) Дык в этом то и соль, что так нельзя.
var_dump((array)false);
// array (size=1)
//   0 => boolean false
echo count((array)false); // 1
Ну да, я имел ввиду что false это тоже что-то, в отличии от null и хпх пытается превратить это в массив что бы посчитать. Немного криво, согласен, но логика ясна хотя бы
мне кажется что это наиболее ожидаемое поведение:
значение null — означает, что переменная не определена или обнулена
значение false — означает, что переменная определена и имеет тип boolean со значением false
В теории, от пользовательского кода, нет.
А как же.
PDO-mysql + attr_emulate_prepares=false + PHP 5.4 + FreeBSD + mod_php — и дело в шляпе.
Может.
Компактные кроссверсионные примеры:
class A
{
    function __destruct()
    {
        return new A;
    }
}
$r=new A;

function e() {
        set_error_handler("e")|A;
        }
e();
А можно поподробнее про
Это потому что ключ FYFY имеет коллизию с EzFY (вообще-то, все ключи из этого массива тоже)
Меня интересует, когда коллизии могут проявлять себя.
Например isset() выдает всё корректно на приведенных ключах.
Перечитал оригинал. Хеш берется от значения, а не от ключа.
Вроде, в потом в оригинале идет «FYFY key collides with EzFY (actually all keys in that array collide)».

Любопытно. Причем, обращаясь к ключу, пхп тоже вычисляет хеш…
Да, про это я в курсе.
Я не понял про совпадение адресов. Ведь при совпадении хешей все равно сравниваются точные значения ключей.
Я не знаток внутренностей, но по первой ссылке написано:
For those who don’t know how hashtables work: When you write $array[$key] in PHP the $key is run through a fast hash function that yields an integer. This integer is then used as an offset into a “real” C array (here “array” means “chunk of memory”).

Because every hash function has collisions this C array doesn’t actually store the value we want, but a linked list of possible values. PHP then walks these values one by one and does a full key comparison until it finds the right element with our $key.
Ну любой хеш так работает (либо я чего-то не знаю). Как я и написал выше:
>>PHP then walks these values one by one and does a full key comparison until it finds the right element
После грубого сравнения хешей (была найдена нужная линия хеша) идет уже точное сравнение значений в пределах связного списка в найденной линии.

Может работать меденно? Да. находить не то? Как? Мне вот не понятно всё еще.
Один вариант: unset освобождает один из элементов линии хеша, и в ту же ячейку записывается новое (другое) значение при присвоении. В итоге внешняя ссылка на эту ячейку остается корректной. Но это имхо.
Да и все равно я такой код, как в примерах статьи, не пишу. И не сталкивался с подобным.
Расскажите подробнее про коллизию хеша из самого последнего примера. У меня шок. Мне страшно дальше писать код!
Sign up to leave a comment.

Articles