Это плохая практика для определения параметров класса через массив? - PullRequest
5 голосов
/ 29 декабря 2010

Когда мы взглянем на Javascript-фреймворки, такие как Dojo, Mootools, jQuery, JS Prototype и т. Д., Мы увидим, что опции часто определяются через массив, подобный этому:

dosomething('mainsetting',{duration:3,allowothers:true,astring:'hello'});

Это плохая практика для реализации той же идеи при написании класса PHP?

Пример:

class Hello {

    private $message = '';
    private $person = '';


    public function __construct($options) {

        if(isset($options['message'])) $this->message = $message;
        if(isset($options['person'])) $this->person = $person;
    }


    public function talk() {

        echo $this->person . ' says: ' . $this->message;
    }
}

Обычный подход:

class Hello {

    private $message = '';
    private $person = '';


    public function __construct() {}


    public function setmessage($message) {

        $this->message = $message;
    }


    public function setperson($person) {

        $this->person = $person;
    }


    public function talk() {

        echo $this->person . ' says: ' . $this->message;
    }
}

Преимущество первого примера состоит в том, что вы можете передать столько параметров, сколько захотите, и класс извлечет только те, которые ему нужны.

Например, это может быть удобно при извлечении опций из файла JSON:

$options = json_decode($options);
$hello = new Hello($options);

Вот как я делаю это регулярно:

$options = json_decode($options);
$hello = new Hello();

if(isset($options['message'])) $hello->setmessage($options['message']);
if(isset($options['person'])) $hello->setperson($options['person']);

Есть ли название для этого паттерна, и вы думаете, что это плохая практика?

Я оставил проверку и т. Д. В примерах для простоты.

Ответы [ 7 ]

12 голосов
/ 29 декабря 2010

Есть хорошие и плохие аспекты.

Товар:

  • Нет необходимости в нескольких сигнатурах методов (т. Е. Перегрузка, где поддерживается)
  • В соответствии с предыдущим пунктом: методы могут вызываться с аргументами в любом порядке
  • Аргументы могут генерироваться динамически, без необходимости указывать каждый из них, который будет присутствовать (пример: вы динамически создаете массив аргументов на основе пользовательского ввода и передаете его функции)
  • Нет необходимости в «стандартных» методах, таких как setName, setThis, setThat и т. Д., Хотя вы, возможно, все же захотите включить их
  • Значения по умолчанию могут быть определены в теле функции, а не в сигнатуре (jQuery часто использует этот шаблон. Они часто $.extend передают методу метод с массивом значений по умолчанию. В вашем случае вы бы использовали array_merge()) * * тысяча двадцать-один

Плохо:

  • Если вы должным образом не рекламируете каждый параметр, ваш класс может быть сложнее использовать, потому что немногие будут знать, какие параметры поддерживаются
  • Это еще один шаг для создания массива аргументов, когда вы заранее знаете, что вам нужно будет передать
  • Для пользователя не всегда очевидно, что значения по умолчанию существуют, если не предоставлена ​​документация или у них нет доступа к исходному коду

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

3 голосов
/ 29 декабря 2010

Когда вы даете имена аргументов, это называется «именованная нотация» v.s. «Позиционная запись», где аргументы должны быть в определенном порядке.

В PHP вы можете передать параметр "options", чтобы дать тот же эффект, что и в других языках (например, Python), где вы можете использовать подлинную именованную нотацию. Это неплохая практика, но часто это делается там, где для этого есть веская причина (т. Е. В вашем примере или в случае, когда есть много аргументов, и их не обязательно устанавливать в каком-то определенном порядке).

3 голосов
/ 29 декабря 2010

В этом подходе нет ничего плохого, особенно если у вас много параметров, которые необходимо передать конструктору.Это также позволяет вам устанавливать значения по умолчанию для них и array_merge() их внутри конструктора (вроде как все плагины jQuery)

protected $default_params = array(
    'option1' => 'default_value'
);
public function __construct($params = array()) {
    $this->params = array_merge($this->default_params, $params);
}

Если вы хотите живые примеры этого "шаблона", проверьте среду Symfony, они используют ее почти везде: вот пример конструктора sfValidatorBase

1 голос
/ 29 декабря 2010

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

Другой возможностью было бы динамическое обращение к установщикам в соответствии с ключом массива параметров, как показано ниже:

public function __construct($options) {
    foreach($options as $option => $value) {
        $method = 'set'.$option;
        if(method_exists($this, $method)
            call_user_func(array($this, $method, $value);
    }
}
1 голос
/ 29 декабря 2010

Если есть обязательные опции, они должны быть в списке параметров конструктора.Затем вы добавляете необязательные опции со значениями по умолчанию.

public function __construc($mandatory1, $mandatory2, $optional1="value", $optional2="value") { }

Если все ваши опции являются необязательными, тогда может быть полезно создать конструктор, принимающий массив.Было бы проще создать объект, чем с помощью «обычного конструктора»: вы могли бы предоставить только те параметры, которые вам нужны, в то время как с «обычным конструктором», если вы хотите указать $ option2, вы должны указать $ option1 (даже установив его).к значению по умолчанию).

1 голос
/ 29 декабря 2010

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

0 голосов
/ 30 июля 2015

Почему бы не сделать оба?Пусть ваш конструктор испечет и съест его тоже со статической фабрикой "именованный конструктор":
$newHello = Hello::createFromArray($options);

Сначала у вас есть конструктор с опциями в порядке.Затем добавьте статический метод, подобный этому, в тот же класс:

public static function createFromArray($options){

    $a = isset($options['a']) ? $options['a'] : NULL;
    $b = isset($options['b']) ? $options['b'] : NULL;
    $c = isset($options['c']) ? $options['c'] : NULL;

    return new Hello($a, $b, $c);
} 

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

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

...