Pull to refresh

Comments 70

Однако такой вариант примерно на 20% медленнее этого:

if (isset($name[49]))
Лолшто?
А если $name в utf?
Так и функция strlen количество байт возвращает.
Так и функция strlen количество байт возвращает.
php> $a = 'асдфгчйкл';

php> echo strlen($a)
18
php> var_dump(isset($a[10]));
bool(true)

php> var_dump(isset($a[15]));
bool(true)

php> var_dump(isset($a[20]));
bool(false)

php> echo mb_strlen($a);
9


Ничего странного не находите?
То что предложенный метод проверки длины строки не работает, вас не смущает.
Окей.
Я думаю автор привел это в качестве примера для последующего разбора, а не как лучший способ проверки длины строки
strlen возвращает кол-во байт в строке, если через mbstring.overload вы его не сломали. В статье приведены конкретные примеры кода до и после.
Я не очень понимаю в чем проблема?
если под длиной строки подразумевать кол-во байт, то проблем нет.
strlen() returns the number of bytes rather than the number of characters in a string.

Само описание функции это предполагает.
Он работает в том контексте, в котором привел его автор. В контексте «длиннее ли строка определенной длины».
if (strlen($name) > 49)
вполне себе аналог
if(isset($name[49]))
вы тоже под длиной строки подразумеваете кол-во байт?
приведенный код отлично решает задачу при использовании однобайтовой кодировки, но фейлит при других.
strlen (без оверрайдинга) считает именно количество байт, не совершайте ошибку используя ее для измерения длины строки в utf
для многобайтовых есть mb_strlen, iconv_strlen и так далее.
я в курсе, что возвращает strlen. и именно об этом писал.
Статья не про подсчет длины строки.
А что тут противоречит моему утверждению?
Тут бы наверное лучше подошел пример с isset() vs array_key_exists(), хоть они и по-разному себя ведут с null
Тут не в этом дело. Нельзя предложенным способом проверять длину строки или получать отдельный символ строки.
С чего вы взяли, что нельзя? В любом коде немало мест, где используется только ascii-часть. Особенно это касается кодовой базы различных фреймворков
gist.github.com/bwg/14a06d3ba51675e514f1
PHP Version 5.5.20-1~dotdeb.1

— Testing isset over 100,000 iterations: (total time in ms)

isset_true 5.856990814209
isset_false 4.7221183776855
array_key_true 16.274929046631
array_key_false 13.417959213257

То есть 10 мс на 100000 операций или 100 нс на одну, в общем в большинстве случаев штуки вроде:

isset($var[$name]) || array_key_exists($name, $var)

лучше всё таки не писать
isset($var[$name]) || array_key_exists($name, $var)

лучше всё таки не писать

Простите, можно уточнить почему так лучше не писать?

Буквально на днях еще заметил приличную разницу между
is_null($var) и $var === null

Может есть какой-то большой список с такими примерами?
Да пишите вы код который легко читать и работает, а не оптимизированный. Оптимизировать надо архитектуру, а не вызовы array_key_exists
В моем случаи уже до меня все «написали», сейчас в основном просят сделать чтоб «не тормозил сайт», переписывать все никто не даст и желаний особо ни у кого нет, поэтому сижу с профайлером и смотрю где проседает скорость, что в кэш, что такими «финтами» заменяю. В целом успехи на лицо. Я не говорю что нужно по всему проекту использовать такое, но если «узкое» место и в кэш не положить, то приходится такое делать.
Да пишите вы код который легко читать и работает

Это вполне сочитается с оптимизацией кода, с оговоркой что лучше это делать на этапе ревью кода.
Даже если вариант с isset был бы на 200 процентов быстрее, то существует 2 основных причины не переходить на него:
  • Сложнее понять что делается в этом коде
  • Основные задерки времени выполнения кода — это не использование менее произодительных конструкций, мы всё-таки не олимпиадным программированием занимаемся и пытаемся прооптимизировать рекурсию на миллион вызовов, а создание конекшенов, выполнение запросов, подключение 100-500 классов фреймворка и т.п.
Тут можно долго спорить, куда уходит процессорное время и память. По моему опыту в 80% случаев можно обойтись isset-ом. Если есть возможность не вызывать функции, лучше этого не делать: xdebug trace скажет только спасибо :)
Но возможно тут немалое значение имеют инструменты, с которыми работаешь. На меня и мой код наибольшее влияение оказали Zend1 и Symfony2, поэтому такие конструкции для меня являются нормой, а для кого-то они покажутся бесполезной или вредной оптимизацией.
Перечитал ваш комментарий, я так понимаю он про isset/strlen. Мой про 80% — про array_key_exists, если что :)
UFO just landed and posted this here
Глупые fb и vk зачем-то решили отказаться от такого классного php в пользу своих решений.
У них другие цели — в первую очередь строгая типизация. Без нее поддержка больших проектов на PHP стоит очень дорого.
Откуда вы это знаете? Hack появился много позже, чем hhvm и тем более hiphop
Это звенья одной цепочки: HipHop -> HHVM -> Hack

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

HHVM: свой интепретатор PHP, более производительный. Но это, скорее всего, переходная платформа, т.к. она поддерживает Hack. Обратная совместимость будет развиваться силами комьюнити, ФБ будет дальше развивать Hack.

Hack: уже интереснее, т.к. он, впринципе, может компилироваться в JVM байт-код — строгая типизация и возвращаемые типы же. Ну и есть свой интерпретатор, опробованный на продакшн серверах.

Вообще ожидайте процесс перетаскивания фич Hack в PHP =)
1. а зачем JVM байт код? у HHVM свой байт-код и свой JIT
2. dim_s со своим JPHP вроде как доказывает что и сейчас ничего не мешает выполнять PHP в JVM

Hack слишком узко применим, по сути кроме как в facebook врятли где еще стоит его использовать + даже внутри facebook я думаю задача взять и переписать все на hack не стоит
1. а зачем JVM байт код? у HHVM свой байт-код и свой JIT
2.… сейчас ничего не мешает выполнять PHP в JVM


1) HHVM — поддерживает и PHP (слабая типизация) и Hack (стогая типизация). Поэтому всё своё (JVM — строгая типизация, поэтому нет полной совместимости).
2) JPHP — «We don’t plan to implement the zend runtime libraries», не для больших продакшн проектов. Да и HHVM выглядит привлекательнее, плюс мощные оптимизации c++ компиляторов.

Hack слишком узко применим, по сути кроме как в facebook врятли где еще стоит его использовать + даже внутри facebook я думаю задача взять и переписать все на hack не стоит

Тут я своего мнения ещё не сформировал окончательно. Но я надеюсь, что примитивные и возращаемые типы перекочуют в PHP как можно быстрее.
JVM байт-код: это так, хотелка. Не обращайте внимания =)
Facebook отказался от использования JVM, где-то в недрах интернета была про это новость, кажется еще в 2012 году. Причин я не помню.
Не думаю — у них же на github хватает проектов на Java.

Плюс когда мы с их рекрутерами общались в Декабре, они чётко обозначили Java + PHP в своих требованиях.
UFO just landed and posted this here
JVM-байткод в… php…


Ну как бы канитель с PHPNG (проект по рефакторингу ядра PHP который будет использоваться в PHP7) как раз таки и затевался что бы можно было внедрить JIT, который я надеюсь, все же добавят. JVM-байткод это конечно тоже вариант что бы не писать свою виртуальную машину… Пользуются же люди JRuby.
UFO just landed and posted this here
Проекты разные бывают, и они живут и развиваются в опредленной инфраструктуре. Большие проекты и инфраструктуру не переписать и не выбросить — это огромные деньги и риски для бизнеса.

Я подозреваю, что для ФБ дешевле допилить Hack, чтобы:
— сохранить команду;
— сохранить работающие решения;
— уменьшить стоимость разработки и сопровождения;

Поэтому будут самые разнообразные проекты PHP/JVM, .NET/JVM, LLVM =)
UFO just landed and posted this here
Ой, я вас умоляю… ну сколько времени и средств займет раздвоить команду и реализовать это все в догоняющем ключе параллельно?

Вы задали правильный вопрос, именно в него и упираются многие решения =)

Но вообще… я понял еще раз одну вещь — в программировании царит вкусовщина.

И авторитаризм, если говорить о процессе разработки софта. Вы правы.
UFO just landed and posted this here
UFO just landed and posted this here
Протестировал на JPHP, вариант с isset работает на 8.5% быстрее strlen, вместо 20%. Итог прост, вызов прямых инструкций байткода будет всегда быстрее вызова метода или функции, даже нативной.
В PHP7 разница 7%:

$ /opt/php-7.0a/bin/php a.php
2.9582719802856
2.7427408695221

Выполняемый код
<?php
$test = str_repeat(0, 100);

$t = microtime(1);
for ($i = 0; $i<1e8; $i++) {
	if (strlen($test) > 49) {
		// nop
	}
}
echo microtime(1) - $t, "\n";

$t = microtime(1);
for ($i = 0; $i<1e8; $i++) {
	if (isset($test[49])) {
		// nop
	}
}
echo microtime(1) - $t, "\n";
Для 100 кк, если быть точным :)
Ах, в миллисекундах… Хитро…
php 5.4 — разница 150%

# php test.php
25.701895952225
10.758450031281

# php test.php
22.53199005127
9.3954191207886

# php -v
PHP 5.4.24 (cli) (built: Jan 13 2014 12:43:37)
Copyright © 1997-2013 The PHP Group
Zend Engine v2.4.0, Copyright © 1998-2013 Zend Technologies
Привет, Николай!

У тебя же вышло 58% разницы(100 × (1 — 9,39/22,53))? Для интереса запустил на PHP 5.6.5:
$ php a.php
11.312389135361
3.878565788269

66%
FYI В PHP7 strlen и еще пара горячих функций были вынесены в отдельный опкод, так что это технически больше не вызов функции, а медленнее из-за `> 49`
Это относится только к функциям которые используют зпп, то есть функции в расширениях (не в пхп коде) и ускорение там совсем небольшое будет, там больше времени съедается на других вещах. Но вообще в 7 уже довольно хорошо ускорили вызов функций.

Кстати эта рфц должна быть уже в апстриме, так что это уже не планы :)
А я еще решил посмотреть насколько свои функции медленнее встроенных. Получилось вот так:
7.34437894821
1.37132811546
20.6537799835
10.7494640350

Версия 5.2

Код
<?php
$test = str_repeat(0, 100);

function myisset($str)
{
	return (isset($test[49]));
}

function mystrlen($str)
{
	return (strlen($test));
}

$t = microtime(1);
for ($i = 0; $i<1e6; $i++) {
    if (strlen($test) > 49) {
        // nop
    }
}
echo microtime(1) - $t, "\n";

$t = microtime(1);
for ($i = 0; $i<1e6; $i++) {
    if (isset($test[49])) {
        // nop
    }
}
echo microtime(1) - $t, "\n";

$t = microtime(1);
for ($i = 0; $i<1e6; $i++) {
    if (mystrlen($test)) {
        // nop
    }
}
echo microtime(1) - $t, "\n";

$t = microtime(1);
for ($i = 0; $i<1e6; $i++) {
    if (myisset($test)) {
        // nop
    }
}
echo microtime(1) - $t, "\n";

UFO just landed and posted this here
По сути да. Преимущество PHP — скорость разработки. Если приходится постоянно сидеть в профилировщике и экономить на вызовах функций, то это помножает на ноль основное достоинство PHP. В таких условиях сменой платформы можно ускорить и работу приложения, и разработку. Другой вопрос, что возможности переписать всё с нуля обычно нет. :)
UFO just landed and posted this here
Не понял насчет:
time() => read $_SERVER['REQUEST_TIME']

Это ж вроде разные вещи.
Для подавляющего большинства применений этого достаточно. Стоит продолжить список, кстати:

is_null(x) → x === null
microtime(true) → $_SERVER["REQUEST_TIME_FLOAT"] (PHP 5.4+)
array_key_exists(…) → isset (с некоторым оговорками, в случае null функция вернёт true, isset — false, если это важно, замена невозможна)
dirname(__FILE__) → __DIR__ (PHP 5.3+)
intval(x) → (int) x (плюс boolval, strval и т.д.)
echo time().PHP_EOL;
echo $_SERVER['REQUEST_TIME'];

1424412119
1424412119

Применительно к указанному вызову time() это одинаковые вещи.
несовсем:

echo $_SERVER['REQUEST_TIME']. PHP_EOL;
sleep(1);
echo time(). PHP_EOL;

даже без sleep этот код может выдавать разные значения
С какой целью вам может потребоваться время ПОСЛЕ выполнения скрипта, длящегося больше секунды?
Обычный кейс для time() — это записать это время в БД, когда произошло что-то типа вставки комментария или чего-то еще.
Логично это время взять как раз таки из времени запроса к серверу.
например если этот скрипт запущен постоянно и через какойнить сервер очередей получает задания для выполнения.
и секунда это достаточно долго, скрипт может быть запущен в 1424412119.95 и уже через 50мс у вас будет разное время
Мы тут об очевидных кейсах использования PHP же говорим, да? В 99% случаев это web-сервер, выполняющий запросы пользователей, в котором php «умирает». И в таких применениях скрипт работающий больше секунды, да еще использующий нестабильное время своего выполнения для чего-то еще — вообще существовать не должен
Статья о том, как смазывать лыжи, чтобы по асфальту они ехали на 20% быстрее?

По-моему, если лишняя микросекунда, потраченная на вызов strlen, существенна в конкретной задаче — то эту задачу не стоило решать на PHP.
Если эта задача (не для РНР) всего одна, опять взникает вопрос о целесообразности иного решения
Sign up to leave a comment.