оптимизация — PHP Laravel Facade __callStatic список аргументов

Не уверен, как правильно назвать это. Копаясь в классах Laravel 4, чтобы посмотреть, как работают Фасады, я наткнулся на это:

Illuminate\Support\Facades\Facades.php@__callStatic

public static function __callStatic($method, $args)
{
$instance = static::getFacadeRoot();

switch (count($args))
{
case 0:
return $instance->$method();

case 1:
return $instance->$method($args[0]);

case 2:
return $instance->$method($args[0], $args[1]);

case 3:
return $instance->$method($args[0], $args[1], $args[2]);

case 4:
return $instance->$method($args[0], $args[1], $args[2], $args[3]);

default:
return call_user_func_array(array($instance, $method), $args);
}
}

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

Часть, которая действительно беспокоит меня, это переключатель.

Зачем нужны случаи от 0 до 4, когда случай по умолчанию будет работать независимо?

Даже если случай 0 имеет смысл, если нет аргументов, зачем использовать случай 1-4, а не просто переходить к случаю 10, например. Есть ли разумные аргументы для этого или это просто случай преждевременной оптимизации?

6

Решение

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

Мне удалось найти эту предоставленную пользователем цитату в ручной записи на call_user_func_array из ‘noone at dot dot com’:

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

Делать очень простой тест также, кажется, подтверждает правильность этого. В результате 1 вызывает метод для экземпляра напрямую, 2 вызывает переменное имя метода для экземпляра, а 3 использует call_user_func_arrayи время вывода в секундах. Количество итераций для каждого подхода составляет 1 000 000.

$ php test.php
(1) total: 0.51281404495239
(2) total: 0.51285219192505
(3) total: 1.1298811435699
$ php test.php
(1) total: 0.49811697006226
(2) total: 0.5209321975708
(3) total: 1.1204349994659
$ php test.php
(1) total: 0.48825788497925
(2) total: 0.51465392112732
(3) total: 1.156769990921

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

Относительно того, почему было выбрано предельное число из 4 параметров, знает только Тейлор. Этот метод (в основном) не изменился со времен Laravel 4.0 первый коммит, и я подозреваю, что это несколько произвольно.

4

Другие решения

Вы правы, звоните call_user_func_array(); отлично работает без использования switch заявление. Но, согласно этому эталонный тест, Это кажется ужасно медленным

function html($value)
{
return htmlentities($value);
}

name            : diff     : total    : description
native          : 0.614219 : 0.613295 : htmlentities($value)
literal_func    : 0.745537 : 1.346594 : html($value)
variable_func   : 0.826048 : 2.162376 : $func($value)
literal_method  : 0.957708 : 3.127519 : $object->html($value)
variable_method : 0.840837 : 3.970290 : $object->$func($value)
call_func       : 1.006599 : 4.993930 : call_user_func($func, $value)
call_object     : 1.193323 : 6.215677 : call_user_func((array($object, $func), $value)
cufa_func       : 1.232891 : 7.320287 : call_user_func_array($func, array($value))
cufa_object     : 1.309725 : 8.769755 : call_user_func_array((array($object, $func), array($value)

Так что в основном это становится проблемой только при использовании call_user_func_array() много раз (так обстоит дело в Laravel). Вот почему они используют switch заявление.

4

Так как $instance->$method() является путь быстрее, чем call_user_func_array,

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

3