php 5.5 — PHP: отправка списка параметров в качестве аргумента (альтернатива именованным параметрам / пакету аргументов)

Я хочу дать список параметров в качестве аргумента функции.

Идеальный сценарий: именованные параметры

Если PHP имеет именованные параметры, это будет сделано так:

function setOptions($title, $url, $public = true, $placeholder = "type here...") {
...
}

setOptions($title = "Hello World", $url = "example.com", $placeholder = "hi");

К сожалению, PHP делает не назвали параметры (пожалуйста, скажите мне, если PHP7 будет иметь некоторые в качестве комментария).

Решение, которое все остальные используют: Ассоциативный массив

Большинство сценариев PHP, которые я видел, используют альтернативный подход к массиву, например так:

function setOptions($options) {
...
}

setOptions(array(
'title' => "Hello World",
'url' => "example.com",
'placeholder' => "hi"));

Недостатки ассоциативного подхода к массиву

Хотя это прекрасно работает, есть следующие недостатки:

  • Пользователь не получает выгоду от автозаполнения (что занимает много времени, чтобы написать)
  • Пользователь может легко делать ошибки в написании
  • Не знаю, какие варианты доступны, поэтому часто может вернуться к документации

Есть ли способ лучше?

Есть ли лучший способ, который может решить эти проблемы (либо в текущем PHP или PHP7 или, может быть, даже hacklang (?)).

1

Решение

В Hack вы можете использовать Формы. Фигуры определяют структуру для ассоциативных массивов, так что вещи могут быть автоматически завершены (в зависимости от поддержки IDE), и ошибки проверки правописания обнаруживаются средством проверки типов.

Например, ваш пример может быть переработан следующим образом:

function setOptions(shape(
'title' => string,
'url' => string,
'public' => ?bool,
'placeholder' => ?string,
) $options) {
$title = $options['title'];
$url = $options['url'];
$public = Shapes::idx($options, 'public', true);
$placeholder = Shapes::idx($options, 'placeholder', 'type here...');
...
}

setOptions(shape(
'title' => 'Hello World',
'url' => 'example.com',
'placeholder' => 'hi',
));

Это знаменует title а также url чтобы оба были обязательными вариантами и public а также placeholder являются необязательными (все обнуляемые типы в формах считаются необязательными). Shapes::idx затем используется для получения предоставленного значения или значения по умолчанию (третий аргумент), если значение не было передано.

1

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

Объявление из массива

Так я обычно объявляю свою структуру классов. Единственным недостатком является то, что запись занимает больше времени, но допускает необязательные параметры, значения по умолчанию и т. Д.

public static $defaults = array(
'user_id' => null,
'username' => null,
'avatar' => null,
'email' => null,
'description' => null,
);

public function __construct(array $args = array()) {
$this->dbc = Database::connection();
$defaults = self::$defaults;
$args = array_merge($defaults, $args);

//Assign the object properites
$this->user_id = (is_numeric($args['user_id'])) ? $args['user_id'] : null;
$this->username = $args['username'];
$this->avatar = AVATAR_DIR . $args['avatar'];
$this->email = $args['email'];
$this->description = $args['description'];
}

Таким образом, вы можете объявить объект как $x = new User()и это будет работать отлично. Допустим, вы выбрали только несколько столбцов из вашего SQL заявление. Вы можете сделать keys в public static $defaults в то же имя, что и columns Вы выбрали этот способ для создания объекта, вы можете легко сделать:

$row = mysqli_fetch_array($result, MYSQLI_ASSOC);
$object = new User($row);

array_merge заботится о наличии любых посторонних ключей, которые вам не нужны в аргументе, который они предоставили. Если вам нужно изменить параметры, вы можете объявить их таким же образом для __construct() с массивом по умолчанию и array_merge поймать аргументы и имитировать именованные параметры и значения по умолчанию (как в Python)

1

Решение: использование беглых сеттеров

Потенциальное решение, которое я нашел для этой проблемы, заключается в использовании классов и беглых сеттеров, например, так:

class PostOptions {

protected
$title,
$url,
$public = TRUE,
$placeholder = "type here..."; //Default Values can be set here

static function getInstance(): PostOptions {
return new self();
}

public function setTitle($title) {
$this->title = $title;
return $this;
}

public function setUrl($url) {
$this->url = $url;
return $this;
}

public function setPublic($public) {
$this->public = $public;
return $this;
}

public function setPlaceholder($placeholder) {
$this->placeholder = $placeholder;
return $this;
}

}

Затем вы можете отправить параметры так:

function setOptions(PostOptions $postOptions) {
//...
}

setOptions(
PostOptions::getInstance()
->setTitle("Hello World")
->setUrl("example.com")
->setPlaceholder("hi")
);

Делать это быстро! (Это выглядит долго)

Хотя это может смотреть долго, это действительно может быть реализовано ОЧЕНЬ быстро с помощью инструментов IDE.

например В InteliJ или PHPStorm просто введите ALT+INS > Выбрать setters > Выберите поля, которые вы хотите установить, и установите флажок для fluent setters > нажмите OK

Почему беглые сеттеры? Почему бы просто не сделать все поля открытыми?

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

$options = new PostOptions();
$options->title = "hello";
$options->placeholder = "...";
$options->url "..."setOptions($options);

Что намного больше печатает по сравнению с предложенным решением

Почему это лучше?

  • Это быстрее в IDE при использовании автозаполнения, чем подход массива
  • Маловероятно допускать ошибки в написании (благодаря автозаполнению)
  • Легко увидеть, какие варианты доступны (опять же, благодаря автозаполнению)
  • Может предоставить индивидуальную документацию для отдельных полей с использованием PHPDoc
  • Можно проще использовать вложенные параметры, например, Если у вас был список опций, и этот вариант также имел больше списка опций
  • Другие преимущества ООП, например наследование & Абстрактные классы

Насколько быстрее этот подход?

Я реализовал быстрый класс для массива меток WordPress в: https://codex.wordpress.org/Function_Reference/register_post_type

Я обнаружил, что установка свойства для каждого значения (с документацией рядом с вами на 2-м мониторе), что подход к установщикам текучих сред примерно равен 25% быстрее, чем подход массива благодаря автозаполнению! Однако, если документация не была рядом с вами, я ожидаю, что этот подход будет намного превышает 25%, как открытие вариантов намного быстрее!

1

С синтаксический: https://github.com/topclaudy/php-syntactic

Вы можете просто сделать:

function foo($a = 1, $b = 2, $c = 3, $d = 4){
return $a * $b * $c * $d;
}

И называйте это аргументами, которые вы хотите:

//Call with argument b only
echo s('foo')->in('b', 5)->out(); //Outputs 60

//Call with argument a and argument at index/position 1 (b),
echo s('foo')->in('a', 7)->in(1, 5)->out(); //Outputs 420

//Call with argument c only through dynamic method
echo s('foo')->c(9)->out(); //Outputs 72
0

Если у вас столько параметров, я бы подумал о создании объекта, который вы передадите в класс вместо n параметров, и каждый параметр — это одно поле. В конструкторе вы вводите необходимые параметры, и тогда это чистое решение.

0
По вопросам рекламы [email protected]