Я хочу дать список параметров в качестве аргумента функции.
Если 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 (?)).
В 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
затем используется для получения предоставленного значения или значения по умолчанию (третий аргумент), если значение не было передано.
Так я обычно объявляю свою структуру классов. Единственным недостатком является то, что запись занимает больше времени, но допускает необязательные параметры, значения по умолчанию и т. Д.
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)
Потенциальное решение, которое я нашел для этой проблемы, заключается в использовании классов и беглых сеттеров, например, так:
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);
Что намного больше печатает по сравнению с предложенным решением
Я реализовал быстрый класс для массива меток WordPress в: https://codex.wordpress.org/Function_Reference/register_post_type
Я обнаружил, что установка свойства для каждого значения (с документацией рядом с вами на 2-м мониторе), что подход к установщикам текучих сред примерно равен 25% быстрее, чем подход массива благодаря автозаполнению! Однако, если документация не была рядом с вами, я ожидаю, что этот подход будет намного превышает 25%, как открытие вариантов намного быстрее!
С синтаксический: 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
Если у вас столько параметров, я бы подумал о создании объекта, который вы передадите в класс вместо n параметров, и каждый параметр — это одно поле. В конструкторе вы вводите необходимые параметры, и тогда это чистое решение.