Производительность PHP при использовании констант вместо строк

Я создаю веб-приложение на чистом PHP, и мне нужно обмениваться некоторым статусом между функциями, этот статус может быть около 5, например: user_created, user_active, user_inactive и так далее. Итак, какой способ сделать это не самый эффективный?

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

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

если не совсем понятно, что я буду делать, очень просто:

function getUserStatus(){
    //return some value
}

а затем используйте его следующим образом

$userStatus = getUserStatus
    switch ($userStatus){
    // all posible cases
}

Если вас беспокоит производительность, вы можете попробовать профилировать оба подхода и посмотреть, какой из них работает лучше. См. Самый простой способ профилировать PHP-скрипт

Phil 22.08.2018 06:21

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

user9886608 22.08.2018 06:44

У вас есть несколько хороших ответов, которые отвечают на ваш настоящий вопрос, поэтому я расскажу о другом. «Я просто пытаюсь оптимизировать каждый аспект своего приложения». Не надо. Не обращайтесь к таким вещам, пока не поймете, что это необходимо. Погуглите "преждевременная оптимизация" и ознакомьтесь с темой. В этом случае лучше рассмотреть возможность сопровождения и ясность кода, и, как отмечали другие, для этого лучше использовать константы. ЭТО причина, по которой вам следует использовать константы. Не экономя лишние микросекунды здесь и там.

Adam Cameron 22.08.2018 08:23
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
2
3
1 303
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Вы можете проверить это примерно так, как показано ниже.

Обратите внимание, что PHP много оптимизирует и хранит скомпилированный байтовый код в своем кеше. http://php.net/manual/en/intro.opcache.php

Результаты, достижения

нить 0,38328790664673 постоянный 0,50211310386658

нить 0,38391804695129 постоянный 0,51568698883057

Что меня удивляет, так это то, что String кажется быстрее.

Я заметил следующую настройку в конфигурации opcache:

opcache.interned_strings_buffer integer
The amount of memory used to store interned strings, in megabytes. 
This configuration directive is ignored in PHP < 5.3.0.

Довольно аккуратная настройка с 0 документацией. PHP использует метод, называемый интернированием строк, для повышения производительности, поэтому, например, если в вашем коде есть строка «foobar» 1000 раз, внутри PHP сохранит одну неизменяемую переменную для этой строки и просто использует указатель на нее для остальных 999 раз вы его используете. Прохладный. Этот параметр выводит его на новый уровень. вместо того, чтобы иметь пул этих неизменяемых строк для каждого ОДНОГО процесса php-fpm, этот параметр разделяет его во ВСЕХ ваших процессах php-fpm. Это экономит память и повышает производительность, особенно в больших приложениях.

Поэтому утверждение, что сравнение строк происходит медленнее, чем сравнение констант, является неправильным предположением в PHP.

НО: вы можете сломать этот пример оптимизации:

$state = "State";
switch($string) {
    case "Offline" . $state:
    break;
}

Результатом этого будет: строка 0,61401081085205 константа 0,51961803436279

В этом случае постоянное сравнение будет быстрее.

Улучшения производительности были добавлены в PHP5.4, и вот RFC https://wiki.php.net/rfc/performanceimprovements

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

function doSomethingString() {
    return "OfflineState";
}

const OFFLINE_STATE = 1;
function doSomethingConstant() {
    return OFFLINE_STATE;
}

function dummy() {}

// String
echo('string' . PHP_EOL);
$start = microtime(true);
for($i = 0; $i < 10000000; $i++) {
    switch(doSomethingString()) {
        case "OfflineState":
            dummy();
            break;
    }
}
echo(PHP_EOL);
$end = microtime(true);
echo($end - $start);
echo(PHP_EOL);


//Constant
echo('constant' . PHP_EOL);
$start = microtime(true);
for($i = 0; $i < 10000000; $i++) {
    switch(doSomethingConstant()) {
        case OFFLINE_STATE:
            dummy();
            break;
    }
}
echo(PHP_EOL);
$end = microtime(true);
echo($end - $start);
echo(PHP_EOL);

Моя версия php:

PHP 7.2.8-1+ubuntu18.04.1+deb.sury.org+1 (cli) (built: Jul 25 2018 10:52:19) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.2.8-1+ubuntu18.04.1+deb.sury.org+1, Copyright (c) 1999-2018, by Zend Technologies

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

user9886608 22.08.2018 06:44

Я просматриваю документы opcache, потому что действительно хочу понять, почему. Возможно, Opcache использует неизменяемые строки или что-то еще под капотом.

Sander Visser 22.08.2018 06:45

Я попробую провести тот же тест на PHP 5.4 и посмотреть, сохраняется ли эта разница.

user9886608 22.08.2018 06:48

Нашел! opcache.interned_strings_buffer, кажется, играет здесь роль, и строки кешируются

Sander Visser 22.08.2018 06:49

Эти настройки создают буфер с неизменяемыми строками, поэтому сравнение строк выполняется быстрее, чем сравнение констант на основе целых чисел.

Sander Visser 22.08.2018 06:50

@Dknacht Я ожидаю, что 5.2 будет работать медленнее со строками или путем настройки параметра opcache (именно так вы обычно оптимизируете большие приложения)

Sander Visser 22.08.2018 06:54

Большой! @Sander Visser, я попробую протестировать эту версию (5.2) и вернусь с результатами, чтобы увидеть, соответствует ли это вашим ожиданиям.

user9886608 22.08.2018 06:56

@Dknacht Я ошибся wiki.php.net/rfc/performanceimprovements вот официальный RFC, реализованный в php 5.4

Sander Visser 22.08.2018 07:11

И добавил пример того, как можно нарушить внутреннюю оптимизацию PHP;) наслаждайтесь тестированием.

Sander Visser 22.08.2018 07:25

jajaja действительно интересно. Спасибо за подробный ответ и всю полную информацию. Мой тест должен быть завтра, потому что здесь уже слишком поздно.

user9886608 22.08.2018 07:59

i know that strings comparison can be quite slow

Это не совсем верно в контексте веб-приложения.

Для сравнения строк требуется микросекунды.

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

Так что такая микрооптимизация вряд ли того стоит. Вместо этого вам следует сосредоточиться на том, что делает код наиболее понятным и удобным в обслуживании.

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

if the PHP parser still needs to read the whole constant name before comparing, is not it the same than using a string, or a variable?

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

«Использование констант (и наличие значений констант в виде чисел, а не строк), вероятно, немного быстрее, чем использование строковых значений» По-видимому, не к моему удивлению

Sander Visser 22.08.2018 06:29

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

user9886608 22.08.2018 06:33

Константы @Dknacht обеспечивают лучшую ремонтопригодность, потому что рефакторинг вашего кода становится проще, и да, это намного важнее

Sander Visser 22.08.2018 06:38

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

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

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

Однако это не обязательно означает, что вам не следует переходить на константы. Реальное преимущество использования констант и строковых литералов для этих типов сравнений заключается в том, что среда выполнения может помочь вам, если вы, скажем, допустили опечатку. Если ваша кодовая база заполнена сравнениями строк типа $var == "some special value", синтаксический анализатор будет более чем счастлив позволить вам ввести опечатку в "some special value" в непонятных областях вашего кода. Однако, если вы используете константы, сравнение, такое как $var == MY_SPECIAL_CONSTANT, предупредит вас, если вы неправильно введете имя константы. Это также позволяет вам определять конкретное значение в одном месте (определение константы), так что если вам когда-либо понадобится его изменить, это будет однострочное изменение вместо огромных усилий по поиску-замене.

Большая часть кода PHP имеет тенденцию быть «строковым программированием», и эти типы кодовых баз могут быть хрупкими и легко восприимчивыми к опечаткам. Константы действительно могут здесь помочь, и именно здесь их ценность, а не производительность.

Сравнение строк кажется быстрее, чем константа, основанная на целых числах (также, к моему удивлению), поэтому утверждение «и это то, чего вы пытаетесь достичь с помощью констант на основе целых чисел», кажется недействительным

Sander Visser 22.08.2018 06:42

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

Jason McClellan 22.08.2018 06:45

Добавил объяснение к моему собственному ответу, opcache имеет настройку для этого opcache.interned_strings_buffer

Sander Visser 22.08.2018 06:52

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

Jason McClellan 22.08.2018 07:03

Другие вопросы по теме