Не уверен, как правильно назвать это. Копаясь в классах 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, например. Есть ли разумные аргументы для этого или это просто случай преждевременной оптимизации?
Я подозреваю, что это микрооптимизация. Я также подозреваю, что для большинства этих статических вызовов на фасады потребуется 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 первый коммит, и я подозреваю, что это несколько произвольно.
Вы правы, звоните 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
заявление.
Так как $instance->$method()
является путь быстрее, чем call_user_func_array
,
Учитывая, что этот фрагмент кода можно вызывать много раз за один цикл, имеет смысл максимально оптимизировать его.