najlepsza praktyka inicjowania członków klasy w php

10

W moich konstruktorach mam dużo takiego kodu: -

function __construct($params) {

    $this->property = isset($params['property']) ? $params['property'] : default_val;

}

Czy lepiej to zrobić, niż określić wartość domyślną w definicji właściwości? tj. public $property = default_val? Czasami istnieje logika dla wartości domyślnej, a niektóre wartości domyślne są pobierane z innych właściwości, dlatego robiłem to w konstruktorze.

Czy powinienem używać seterów, aby cała logika wartości domyślnych była oddzielona?

rgvcorley
źródło

Odpowiedzi:

8

Wcześniej miałem ze sobą tego rodzaju filozoficzną debatę. Oto, gdzie stoję przez większość czasu, chociaż zdaję sobie sprawę, że jest to odpowiedź oparta na opiniach:

Jedną rzeczą, która może pomóc w odpowiedzi na pytanie, jest przekazanie $ params, które mogą mieć lub nie mieć ustawionych atrybutów / elementów tablicy.

Przez lata doszedłem do tego wniosku:

Unikaj przekazywania tablic.

Dlaczego? Cóż, nie ma możliwości ustawienia ani zdefiniowania wartości wartowników dla opcjonalnie przekazywanych argumentów.

Innymi słowy, przy użyciu podanego kodu nie można zrobić czegoś takiego:

function __construct($arg1 = NULL, $arg2 = DEFAULT_VAL) {

    $this->arg1 = $arg1;

    $this->arg2 = $arg2;

}

$ arg1 i $ arg2 są opcjonalnymi argumentami - jeśli nie zostaną przekazane, mają odpowiednio NULL i DEFAULT_VAL - nie trzeba jawnie sprawdzać.

Może wydaje się to trochę arbitralne.

Myślę, że dostaję to, co próbujesz osiągnąć - przekazanie jednego odwołania w przeciwieństwie do mnóstwa argumentów. To prowadzi mnie do następnego wniosku:

Jeśli nie przekazujesz zmiennych „atomowych” (ciągi, liczby całkowite, literały), to przekazuj obiekty.

Są tutaj korzyści związane z wydajnością, ponieważ przekazywanie obiektów odbywa się przez odniesienie (chociaż tablice, moim zdaniem, są mniej więcej takie same w PHP).

Więc możesz zrobić coś takiego:

function __construct(MyAwesomeObject $oArg) {

        $this->oArg = $oArg;

    }

Gwarantuje się, że przekazany argument obiektowy będzie miał „właściwość 1”, „właściwość 2”, choć możliwe, że same wartości domyślne.

Dodatkowo tutaj możesz wpisać podpowiedź, a dobre IDE również poprawnie automatycznie zasugeruje uzupełnienie kodu.

Ale szybko zdajemy sobie sprawę, że mamy coś z kurczakiem i jajkiem: konstruujesz obiekt z przekazanymi argumentami obiektowymi, które w pewnym momencie muszą zostać skonstruowane.

Więc gdzie nas to opuszcza? Doszedłem do wniosku, że ostatecznie wszystkie klasy destylują się do, z braku lepszego terminu, zmiennych „atomowych” (łańcuchy, liczby zmiennoprzecinkowe, liczby podwójne, liczby całkowite, zasoby, o które mi chodzi), i że zwykle próbuję konstruować wszystkie klasy z tymi typami zmiennych lub obiektami - ale nie tablicami.

Czy więc odpowiedziałem na twoje pytanie? prawdopodobnie nie do końca. Mam jednak nadzieję, że zilustrowałem coś przydatnego, choć nieco stylistycznego. Myślę, że kod jest nieco czystszy, bardziej czytelny i tańszy.

Nie oznacza to, że nie powinieneś dezynfekować danych wejściowych. To zupełnie kolejna dyskusja.

Mam nadzieję że to pomoże.

ekeyser
źródło
1
To dobra uwaga i bardzo przydatna dla podpowiedzi IDE, ale jest zbyt wiele właściwości obiektów, aby przekazać je wszystkie jako parametry. Jeśli masz 7 argumentów, powiedz, że 5 z nich jest opcjonalnych, skończysz z takimi rzeczami, new object($param1,-some default value so I can specify the next parameter-, $param3);a więc masz domyślne wartości
zapisane na stałe
3

Chociaż staram się unikać przekazywania tablic do konstruktora, czasami uważam, że konieczne jest przetworzenie przychodzącej wartości tablicy (na przykład dla klasy, która odczytuje wartości z pliku konfiguracyjnego).

W takim przypadku skorzystam z funkcji tablicowych PHP, aby upewnić się, że pracuję z dokładnie tym, z czym myślę, że pracuję:

public function import( array $incoming )
{
  $defaults = array(
      'foo' => DEFAULT_FOO
    , 'bar' => DEFAULT_BAR
    ...
  );

  $values = array_merge($defaults, array_intersect_key($incoming, $defaults));

  ...
}

Ten ostatni wiersz używa array_merge()do zastąpienia dowolnych wartości $defaultsodpowiednimi wartościami z $incoming. Używam również, array_intersect_key()aby upewnić się, że tablica wynikowa nie zawiera żadnych dodatkowych kluczy, których klasa / metoda nie wiedziałaby, jak przetworzyć.


źródło
Cześć, co się dzieje, jeśli $ defaults zawiera tablicę zamiast prostych zmiennych?
Pol Dellaiera,
@PolDellaiera Spójrz na array_merge_recursive.