Эмуляция названных параметров функции в PHP, хорошая или плохая идея?

Именованные параметры функции могут быть эмулированы в PHP, если я пишу такие функции

function pythonic(array $kwargs) { extract($kwargs); // .. rest of the function body } // if params are optional or default values are required function pythonic(array $kwargs = array('name'=>'Jon skeet')) { extract($kwargs); // .. rest of the function body } 

Помимо потери intellisense в среде IDE, каковы другие возможные недостатки этого подхода?

Редактировать:

Безопасность. В этом случае безопасность не должна быть проблемой, поскольку выделенные переменные ограничены функциональной областью?

Related of "Эмуляция названных параметров функции в PHP, хорошая или плохая идея?"

Я бы предложил использовать ассоциативный массив для передачи именованных параметров, но сохранить их в массиве без их извлечения.

 function myFunc(array $args) { echo "Hi, " . $args['name']; // etc } 

Для этого есть несколько причин. Глядя на эту функцию, вы вполне можете ясно видеть, что я имею в виду один из аргументов, переданных в функцию. Если вы их извлечете и не заметите extract() вы (или следующий парень) будете царапать голову, задаваясь вопросом, откуда взялась эта переменная « $name ». Даже если вы знаете, что вы извлекаете аргументы в локальные переменные, в какой-то степени это догадка.

Во-вторых, он гарантирует, что другой код не перезаписывает аргументы. Возможно, вы написали свою функцию, ожидая только наличия аргументов с именем $foo и $bar , поэтому в вашем другом коде вы определяете $baz = 8; , например. Позже вы можете расширить свою функцию, чтобы принять новый параметр под названием «baz», но забудьте изменить другие переменные, поэтому независимо от того, что передается в аргументах, $baz всегда будет установлен на 8.

Есть несколько преимуществ использования массива (они одинаково применимы к методам извлечения или ухода в массиве): вы можете настроить переменную в верхней части каждой функции с именем $defaults :

 function myFunc (array $args) { $default = array( "name" => "John Doe", "age" => "30" ); // overwrite all the defaults with the arguments $args = array_merge($defaults, $args); // you *could* extract($args) here if you want echo "Name: " . $args['name'] . ", Age: " . $args['age']; } myFunc(array("age" => 25)); // "Name: John Doe, Age: 25" 

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

Вот еще один способ сделать это.

 /** * Constructor. * * @named string 'algorithm' * @named string 'mode' * @named string 'key' */ public function __construct(array $parameter = array()) { $algorithm = 'tripledes'; $mode = 'ecb'; $key = null; extract($parameter, EXTR_IF_EXISTS); //... } 

С этой настройкой вы получаете параметры по умолчанию, вы не теряете intellisense в IDE, а EXTR_IF_EXISTS делает его защищенным, просто извлекая ключи массива, которые уже существуют как переменные.

(Кстати, создание значений по умолчанию из приведенного вами примера не очень хорошо, потому что если массив параметров предоставляется без индекса «name», ваше значение по умолчанию будет потеряно.)

По моему опыту, этот подход действительно полезен, если одна из двух вещей истинна

  1. По каким-либо смягчающим причинам, ваш аргумент большой. Я как бы прохожу на 6 максимум – не по какой-то конкретной причине, хотя кажется правдой, но я свободно признаю, что это число произвольно.
  2. Все или многие из ваших аргументов являются необязательными, и иногда вам нужно только установить значение для 5-го или нескольких таких штук. Это раздражает писать someFunc( null, null, null, null, 1 );

Если любой из них верен для вас, подделка с именем params с ассоциативным массивом может быть правильной реализацией. Помимо того, что, зная, когда избегать извлечения (или вообще избегать его), я не могу сразу думать о других недостатках.

При этом, как правило, обе эти проблемы могут быть решены с помощью рефакторинга.

По моему опыту, недостатком этого метода является больше кода для написания. рассмотрим что-то вроде этого:

 function someFunc($requiredArg, $arg1 = "default11", $arg2 = "default2") { 

Чтобы моделировать это поведение при передаче всего в массиве, вам нужно написать больше кода, а «подпись функции» будет менее «понятной и очевидной».

 function someFunc($requiredArg, $optionalArgs) { // see other answers for good ways to simulate "named parameters" here 

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

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

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

Безопасность. В этом случае безопасность не должна быть проблемой, поскольку выделенные переменные ограничены функциональной областью?

Да и нет. Код, который вы написали, может (в зависимости от того, всегда ли вы инициализируете переменные после этого вызова) перезаписывает ваши вары. Пример:

 function pythonic(array $kwargs = array('name'=>'Jon skeet')) { $is_admin = check_if_is_admin(); // initialize some variable... extract($kwargs); // Q: what is the value of $is_admin now? // A: Depends on how this function was called... // hint: pythonic([ 'is_admin' => true ]) } 

Что делает этот код «незащищенным», так это то, что ВЫ – тот, кто его вызывает, – поэтому пользователь не может предоставить произвольные параметры (если вы, конечно, не перенаправляете POST-вары;).

Как правило, вы должны избегать такой магии. Линия с extract() может иметь непреднамеренные побочные эффекты, поэтому вы не должны ее использовать. На самом деле, я не могу думать о законном использовании функции extract () в любом приложении (я не думаю, что когда-либо использовал его сам).