melhores práticas para inicializar os membros da classe em php

10

Eu tenho muitos códigos como este em meus construtores: -

function __construct($params) {

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

}

É melhor fazer isso em vez de especificar o valor padrão na definição da propriedade? ie public $property = default_val? Às vezes, há lógica para o valor padrão, e alguns valores padrão são obtidos de outras propriedades, e foi por isso que eu estava fazendo isso no construtor.

Devo usar setters para que toda a lógica dos valores padrão seja separada?

rgvcorley
fonte

Respostas:

8

Eu já tive esse tipo de debate filosófico comigo antes. Aqui é onde estou na maior parte do tempo, embora perceba que essa é uma resposta baseada em opinião:

Uma coisa que vejo que pode ajudar a responder à pergunta é a passagem de $ params, que pode ou não ter atributos / membros de matriz definidos.

Ao longo dos anos, cheguei a esta conclusão:

Evite a passagem de matrizes.

Por quê? Bem, não há como definir ou ter valores de sentinela definidos para argumentos passados ​​opcionais.

Em outras palavras, com o código especificado, você não pode fazer algo assim:

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

    $this->arg1 = $arg1;

    $this->arg2 = $arg2;

}

$ arg1 e $ arg2 são argumentos opcionais - se não forem passados, têm NULL e DEFAULT_VAL respectivamente - não há necessidade de verificar explicitamente.

Talvez isso pareça meio arbitrário.

Eu acho que entendo o que você está tentando realizar - a aprovação de uma única referência em oposição a toneladas de argumentos. Isso me leva à minha próxima conclusão:

Se não passar variáveis ​​"atômicas" (cadeias, números inteiros, literais), passe objetos.

Existem benefícios de desempenho aqui, pois a passagem de objetos é feita por referência (embora as matrizes sejam as mesmas no PHP).

Então você pode fazer algo como:

function __construct(MyAwesomeObject $oArg) {

        $this->oArg = $oArg;

    }

O argumento do objeto passado teria a garantia de ter "property1", "property2", embora possivelmente com os próprios valores padrão.

Além disso, aqui você pode digitar dica e um bom IDE também sugerirá corretamente a conclusão do código.

Mas rapidamente percebemos que temos uma coisa de galinha e ovo: você está construindo um objeto com argumentos passados ​​que precisam ser construídos em algum momento.

Então, onde isso nos deixa? Bem, cheguei à conclusão de que, eventualmente, todas as classes se destilam para, por falta de um termo melhor, variáveis ​​"atômicas" (strings, floats, dobros, ints, recursos que você entende) e que eu tento para construir todas as classes com esses tipos ou objetos variáveis ​​- mas não matrizes.

Então eu respondi sua pergunta? provavelmente não exatamente. Mas espero ter ilustrado algo útil, embora um pouco estilístico. Eu acho que o código é um pouco mais limpo, mais legível e mais barato.

Agora, isso não quer dizer que você não deve higienizar sua entrada. Essa é outra discussão inteiramente.

Espero que isto ajude.

ekeyser
fonte
11
É um bom ponto, e muito útil para prompts do IDE, mas há muitas propriedades de objetos para passar todas elas como parâmetros. Se você tem 7 argumentos dizer 5 dos quais são opcionais você acabar com coisas como new object($param1,-some default value so I can specify the next parameter-, $param3);e por isso você tem seus valores padrão codificados em vários lugares diferentes
rgvcorley
3

Embora eu evite passar matrizes para um construtor, às vezes acho necessário processar um valor de matriz recebido (como uma classe que lê valores de um arquivo de configuração).

Em um caso como esse, aproveitarei as funções de matriz do PHP para garantir que estou trabalhando exatamente com o que acho que estou trabalhando:

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

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

  ...
}

Essa última linha usa array_merge()para substituir qualquer valor $defaultspelos valores correspondentes de $incoming. Também uso array_intersect_key()para garantir que a matriz resultante não contenha nenhuma chave extra que a classe / método não saiba processar.


fonte
Olá, qual é o comportamento se $ default contém uma matriz em vez de variáveis ​​simples?
Pol Dellaiera
@PolDellaiera Olhe para array_merge_recursive.