Комментарии 37
Be aware: в новом phpng (потенциальный php 5.7) все будет немного по-другому.
+3
+1. Кстати, именно этот доклад побудил меня перевести эту книгу. Я слушал этот доклад и в зале слышал комментарии типа: «о чем это?», «ничего непонятно». То есть не все PHP-разработчики задумываются о том как работает PHP, а это знание может быть полезным.
+4
Доклад был отличный, это да! А про zval и остальное на русском действительно многим полезно почитать будет, включая меня самого :)
Насчет phpng — я так понял (вполне возможно, что неправильно), что прирост производительности при работе с HashTable будет в каких-то одних случаях, а в других будет что-то вроде fallback к старому варианту и соответственно никакой выгоды. Но я не запомнил, о каких случаях шла речь. Буду рад, если кто подскажет.
Насчет phpng — я так понял (вполне возможно, что неправильно), что прирост производительности при работе с HashTable будет в каких-то одних случаях, а в других будет что-то вроде fallback к старому варианту и соответственно никакой выгоды. Но я не запомнил, о каких случаях шла речь. Буду рад, если кто подскажет.
0
Тут вот какой кейс — часто пхп-шный «массив» используется как настоящий массив (как массив в си например), поэтому сделана такая фича:
если HashTable.u.flags | HASH_FLAG_PACKED > 0, значит что элементы массива располагаются просто по порядку (скорее всего он был собран как-нибудь так $ar = []; $ar[] = 1; $ar[] = 42; и т.д.), а значит мы не нуждаемся в хеш таблице как таковой => HashTable.arHash — не инициализирован в данный момент (тут мы экономим память) и если юзер пытается получить доступ к какому-либо элементу, вместо хеширования и лукапа в хеш-таблицу нам надо лишь получить элемент по оффсету (предварительно проверив, конечно, что ключ — не out of bounds), что сэкономит немного времени. Если юзер решит добавить элемент со строковым ключом, или с численным ключом значение которого не равно HashTable.nNextFreeElement — то делаем rehash с убранным флагом HASH_FLAG_PACKED.
если HashTable.u.flags | HASH_FLAG_PACKED > 0, значит что элементы массива располагаются просто по порядку (скорее всего он был собран как-нибудь так $ar = []; $ar[] = 1; $ar[] = 42; и т.д.), а значит мы не нуждаемся в хеш таблице как таковой => HashTable.arHash — не инициализирован в данный момент (тут мы экономим память) и если юзер пытается получить доступ к какому-либо элементу, вместо хеширования и лукапа в хеш-таблицу нам надо лишь получить элемент по оффсету (предварительно проверив, конечно, что ключ — не out of bounds), что сэкономит немного времени. Если юзер решит добавить элемент со строковым ключом, или с численным ключом значение которого не равно HashTable.nNextFreeElement — то делаем rehash с убранным флагом HASH_FLAG_PACKED.
+6
Спасибо за замечательное разъяснение! Теперь до меня дошло.
+3
А как только добавили элемент не по порядку, это всё начнёт копироваться в хеш?
0
И да и нет, на самом деле там несколько условий, проще будет объяснить в коде:
Вроде ничего не забыл, в общем-то это выжимка из этого кода, почитайте лучше его, если закомы с си и пхп на том уровне.
function set($arr, $key, $val)
{
...
if ($arr->flags & HASH_FLAG_PACKED) {
if ($key < 0) {
goto convert_to_hash;
}
if ($key < $arr->lastUsedKey) {
if ($arr->data[$key]->type !== TYPE_VAR_UNDEFINED) { // TYPE_VAR_UNDEFINED в данном случае значит что это неинициализированная переменная (ей ничего не присвоили, даже null)
// добавим этот элемент в массив, он должен нормально туда влезть, заменив какой-то из уже существующих по этому индексу
} else {
// если по такому ключу ничего нет (но при этом после него есть ключи, которые мы использовали), то превращаемся в хештаблицу, т.к. только с ней мы сможем соблюсти такой порядок элементов
goto convert_to_hash;
}
} elseif ($key < $arr->tableSize) { // если ключ больше самого большого ключа из этого массива, но меньше чем кол-во заранее инициализированных бакетов (это число всегда кратно 2)
// просто добавим этот элемент сюда
} elseif ($key < $arr->tableSize * 2 && $arr->tableSize - $arr->lastUsedKey < $arr->tableSize / 2) { // если ключ больше чем кол-во преинициализированных бакетов, но меньше чем это же число умноженное на два, и при этом если мы уже используем больше половины бакетов
// инициализировать в два раза больше бакетов чем есть сейчас, и переместить туда их
// добавить элемент
} else {
goto convert_to_hash;
}
}
convert_to_hash:
...
}
Вроде ничего не забыл, в общем-то это выжимка из этого кода, почитайте лучше его, если закомы с си и пхп на том уровне.
+3
Да доклад был замечательный. Жаль видео записи нет. А по поводу того что не все PHP-разработчики задумываются о том как работает PHP можно даже по другому сказать( более эпичнее что ли ), Не более 10-20 процентов знают что такое Zend Engine, и не более 5 процентов знают что такое zval, а уж про то сколько всего разработчиков понимают как оно работает и вовсе молчу. я сам грешен буквально пару лет назад из 6 лет работы с php узнал что такое zval и как он работает. И более чем уверен что у меня ещё есть прорехи в знаниях. Кстати может кто нибудь сам записывал доклад на видео? А то похоже от организаторов не дождёмся. Там даже презентации не все есть.
Кстати rrromka приведённый в начале пример не имеет никакого отношения к Zval.
Кстати rrromka приведённый в начале пример не имеет никакого отношения к Zval.
0
Кстати rrromka приведённый в начале пример не имеет никакого отношения к Zval.
Почему? Я этим примером хотел показать, что функция
f1
меняет тип переданного zval-а, по этому внутри неё срабатывает copy-on-write и объект снаружи функции остается без изменения. Функция f2
тип не меняет, по этому копироания-при-записи нет и меняется zval снаружи функции.+1
Начнём с того что наверное для меня такое поведение очевидно даже без знания Zval.
А далее причём тут вообще тип?
А далее причём тут вообще тип?
+2
Я согласен с тем, что программируя на PHP можно обойтись без знания о том что такое zval. Но если вы хотите разобраться почему именно в приведенном примере функции
Отличие между этими двумя функциями на уровне zval-ов заключается в том, что первая меняет lval и type переданного объекта, что вызывает copy-on-write. Вторая не трогает lval и type, а работает только с zend_object_value.
Как бы вы объяснили разницу в работе этих функций без упоминания zval-ов?
f1
и f2
ведут себя по разному, то понимать структуру zval и zvalue_value нужно.Отличие между этими двумя функциями на уровне zval-ов заключается в том, что первая меняет lval и type переданного объекта, что вызывает copy-on-write. Вторая не трогает lval и type, а работает только с zend_object_value.
Как бы вы объяснили разницу в работе этих функций без упоминания zval-ов?
-2
Ну это понятно из док. Обе функции принимают значения. Но объекты — это ссылочный тип (тип значения). Так что в первой вы меняете переменную (меняете ее значение) в другом скоупе, поэтому она и не изменяется в глобальном. А во второй функции вы работаете с самим объектом (значением аргумента), который является ссылкой. Как-то запутанно это объяснять, но по-моему это не пересекается со знаниями о том, как это устроено внутри.
+3
А зачем вешать специфическую статью про PHP в общий хаб «Программирование»?
+1
Непонятная логика. Следуя ей статьи про Java, C++, Haskell и другие языки тоже не нужно в этот хаб вешать.
+3
Ключевое слово здесь «специфическую».
Товарищ Zigmar, видимо, хотел сказать нам, что общий хаб «Программирование» задуман для повествования о вещах в том или ином виде применимых в большинстве языков, а для описания узко-специфичных конструкций одного конкретного языка существуют специализированные хабы.
С уважением.
Товарищ Zigmar, видимо, хотел сказать нам, что общий хаб «Программирование» задуман для повествования о вещах в том или ином виде применимых в большинстве языков, а для описания узко-специфичных конструкций одного конкретного языка существуют специализированные хабы.
С уважением.
+7
Именно. Вывешивание узконаправленных статей в общие хабы ломает систему фильтрации. Я например подписан на хабы языков, которые мне интересны плюс на хаб «программирование» по общепрограммисткой тематике. Если все статьи вешать и туда и туда, то не будет способа отфильтровать интересующий вас контент.
+5
Ещё года два назад на собеседованиях любили спрашивать: «Какова алгоритмическая сложность (в О-нотации) функции strlen($s) в PHP»
Надеюсь, прочитавшие эту статью сразу смогут ответить на этот вопрос.
Надеюсь, прочитавшие эту статью сразу смогут ответить на этот вопрос.
0
А что (вопрошающие) считали правильным ответом? O(N) или O(1)?
0
Вопрошающие знали ответ O(1), но я не уверен в том, что все знали почему.
В одной компании раскритиковали мой ответ: \Theta(1).
В одной компании раскритиковали мой ответ: \Theta(1).
+1
Для того, чтобы предположить правильный ответ на этот вопрос, мне достаточно знать, что в строке может содержаться нулевой байт. Если это так, то в большинстве случаев строка состоит из пары (указатель на начало строки, длина строки). Для людей, пишущих на C, причины именно такого решения понятны.
Правда, если вы предположите такое в отношении zsh (а там ноль может быть внутри строки, если только вы не запретили ему там быть с помощью настроек), то вы прогадаете, но других языков, использующих для хранения бинарных строк экранирование я просто не знаю.
Правда, если вы предположите такое в отношении zsh (а там ноль может быть внутри строки, если только вы не запретили ему там быть с помощью настроек), то вы прогадаете, но других языков, использующих для хранения бинарных строк экранирование я просто не знаю.
0
Я ответ определил сразу и не вижу никаких причин по которым он может быть иным.
При этом с тонкостями zval не знаком и не вижу, как они связаны с этим примером.
При этом с тонкостями zval не знаком и не вижу, как они связаны с этим примером.
+7
Плюсую, потому что эти вещи довольно чётко описаны в руководстве по языку и для их понимания о внутренностях знать не обязательно.
0
Зато вопрос в комментарии выше вы не определите без знания внутренностей. А это знание довольно полезно.
+1
А его не надо определять, можно просто помнить.
-2
Это подход кодера, а не программиста. Это как математик, который не помнит формул, но может их всегда вывести.
+4
Кажется наоборот, который помнит, но не понимает откуда эти формулы.
+2
Ну то есть, вы мне сейчас сможете рассказать, начиная с физических принципов, как это всё хранится, какое значение имеет выравнивание, как данные могут оказаться в свопе, как работает DMA в защищённом режиме и так далее?
Я, кстати, это рассказать смогу. Но как устроен zval мне не интересно.
Я, кстати, это рассказать смогу. Но как устроен zval мне не интересно.
-1
Не так давно на Хабре была статья про неумение сборщика мусора работать с циклическими ссылками. Я так понимаю, это исправили начиная с какой-то версии?
0
Да, с версии 5.3: www.php.net/manual/ru/features.gc.collecting-cycles.php.
+1
С выхода 5.3, где это исправили, прошло 5 (!) лет. Ничего себе «не так давно».
0
Если у меня еще раз кто-нибудь спросит, почему я не люблю php, я просто покажу первый пример кода из этой статьи.
-10
НЛО прилетело и опубликовало эту надпись здесь
Если кому интересна данная тема, то есть хорошая книжка (с переводом на русский) «Профессиональное программирование на PHP» Джордж Шлосснейгл. Часть материала — как раз по начинке php.
0
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Изучаем PHP изнутри. Zval