Getter e Setter?

203

Eu não sou desenvolvedor de PHP, por isso estou me perguntando se no PHP é mais popular usar getter / setters explícitos, em um estilo OOP puro, com campos privados (do jeito que eu gosto):

class MyClass {
    private $firstField;
    private $secondField;

    public function getFirstField() {
        return $this->firstField;
    }
    public function setFirstField($x) {
        $this->firstField = $x;
    }
    public function getSecondField() {
        return $this->secondField;
    }
    public function setSecondField($x) {
        $this->secondField = $x;
    }
}

ou apenas campos públicos:

class MyClass {
    public $firstField;
    public $secondField;
}

obrigado

Marca
fonte
7
Depois de tentar algum código das respostas, usei o código que você está usando na pergunta. Como triste :-(
sumid
9
PHPstorm ... gera> getters e setters. == vitória
DevDonkey 14/07
@DevDonkey Nem uma vitória. Para manter dados estruturados, use matrizes. @: Marcar Não é para isso que os objetos servem ou são. Getters e setters são maus: yegor256.com/2014/09/16/getters-and-setters-are-evil.html
Kubo2 17/01

Respostas:

222

Você pode usar métodos mágicos php __get e __set.

<?php
class MyClass {
  private $firstField;
  private $secondField;

  public function __get($property) {
    if (property_exists($this, $property)) {
      return $this->$property;
    }
  }

  public function __set($property, $value) {
    if (property_exists($this, $property)) {
      $this->$property = $value;
    }

    return $this;
  }
}
?>
Davis Peixoto
fonte
15
Eu acho que você quer dizer __gete __set. Existem dois sublinhados, não um. Aqui está o link direto para a parte direita da página: php.net/manual/en/… (+1 para uma resposta correta)
Computerish
28
Qual é o benefício contra publicpropriedades, se não houver validação / saneamento?
KingCrunch 14/05
7
@ KingCrunch, este é apenas um exemplo. Um exemplo muito fictício para um recurso poderoso.
Davis Peixoto
10
Isso não é realmente intrigante. Normalmente, preciso para cada propriedade uma implementação diferente do getter!
sumid
79
Por favor, não: Com métodos mágicos, você PERDERÁ quase todos os recursos relacionados à qualidade, em muitos IDE (inclusive no vim): preenchimento automático, herança explícita do PHP, interpretação rápida do PHP e geração e saída úteis do PHPDoc. cf. stackoverflow.com/a/6184893/490589
Ronan
113

Por que usar getters e setters?

  1. Escalabilidade : é mais fácil refatorar um getter do que pesquisar todas as atribuições de var em um código de projeto.
  2. Depuração : você pode colocar pontos de interrupção em setters e getters.
  3. Limpador : As funções mágicas não são uma boa solução para escrever menos, seu IDE não sugere o código. Modelos de uso melhor para getters de escrita rápida.

atribuição direta e getters / setters

Wiliam
fonte
7
Se você usar @property, seu IDE sugerirá o código (testado com o PhpStorm 7) #
Alex2php
41

O Google já publicou um guia sobre otimização de PHP e a conclusão foi:

Sem getter e setter Otimizando o PHP

E não, você não deve usar métodos mágicos . Para PHP, o Magic Method é mau. Por quê?

  1. Eles são difíceis de depurar.
  2. Há um impacto negativo no desempenho.
  3. Eles exigem escrever mais código.

PHP não é Java, C ++ ou C #. PHP é diferente e desempenha papéis diferentes.

Magallanes
fonte
10
Eu tendem a concordar com essa ideia; isso $dog->name = 'fido'é melhor que $dog->setName('fido'). Quando realmente mutação de um imóvel (ex: $dog->increaseAge(1). Eu posso construir o método que faz a validação e sofre mutações necessário que a propriedade Mas nem todas as ações realmente necessitam mutação nesse sentido.
Charlie Schliesser
11
O artigo não diz " não ", ele diz 'setters e getters ingênuos'.
Brett Santore
13
É seguro assumir que um artigo escrito pelo Google com o título "Dicas de desempenho do PHP" NÃO pretende sugerir um bom estilo de codificação, mas uma execução rápida do código. O capítulo que trata de setters e getters é rotulado como "Evite escrever setters e getters ingênuos", e o exemplo de código é exatamente isso: ingênuo. Ele define e obtém apenas uma variável sem nenhuma validação. ESTE tipo de setter / getter é inútil. Fazer a validação dentro de um setter (basta usar uma dica de tipo para o argumento do método) tornará os setters / getters úteis, porque agora seu código SABE com o que está lidando.
Sven
3
é como dizer que o estilo embutido é melhor. claro que o desempenho é melhor, mas é um código melhor? Eu não sabia o google engenheiros usar php qualquer maneira
Claudiu Creanga
13

O encapsulamento é importante em qualquer idioma OO, a popularidade não tem nada a ver com isso. Em linguagens tipadas dinamicamente, como PHP, é especialmente útil porque existem poucas maneiras de garantir que uma propriedade seja de um tipo específico sem o uso de setters.

No PHP, isso funciona:

class Foo {
   public $bar; // should be an integer
}
$foo = new Foo;
$foo->bar = "string";

Em Java, não:

class Foo {
   public int bar;
}
Foo myFoo = new Foo();
myFoo.bar = "string"; // error

O uso de métodos mágicos ( __gete __set) também funciona, mas somente ao acessar uma propriedade com menor visibilidade do que o escopo atual pode acessar. Ele pode facilmente causar dores de cabeça ao tentar depurar, se não for usado corretamente.

codificador de rede
fonte
7
Getters e setter não trazem encapsulamento. Objetos de encapsulamento == fazem algo com seus próprios dados em vez de fornecê-los para fora. Getters e setters não são uma ferramenta para impor tipos em linguagens dinamicamente tipadas como PHP.
S05
14
@smentek: Você está claramente perdendo pelo menos metade do que realmente é o encapsulamento.
Netcoder 15/05
2
Como uma atualização para quem estiver procurando, o PHP 7.4 virá com suporte a propriedades digitadas. Então, você poderia declarar $barcomo intno primeiro exemplo: wiki.php.net/rfc/typed_properties_v2
Kevin
7

Se você preferir usar a função __call, poderá usar este método. Trabalha com

  • GET => $this->property()
  • SET => $this->property($value)
  • GET => $this->getProperty()
  • SET => $this->setProperty($value)

kalsdas

public function __call($name, $arguments) {

    //Getting and setting with $this->property($optional);

    if (property_exists(get_class($this), $name)) {


        //Always set the value if a parameter is passed
        if (count($arguments) == 1) {
            /* set */
            $this->$name = $arguments[0];
        } else if (count($arguments) > 1) {
            throw new \Exception("Setter for $name only accepts one parameter.");
        }

        //Always return the value (Even on the set)
        return $this->$name;
    }

    //If it doesn't chech if its a normal old type setter ot getter
    //Getting and setting with $this->getProperty($optional);
    //Getting and setting with $this->setProperty($optional);
    $prefix = substr($name, 0, 3);
    $property = strtolower($name[3]) . substr($name, 4);
    switch ($prefix) {
        case 'get':
            return $this->$property;
            break;
        case 'set':
            //Always set the value if a parameter is passed
            if (count($arguments) != 1) {
                throw new \Exception("Setter for $name requires exactly one parameter.");
            }
            $this->$property = $arguments[0];
            //Always return the value (Even on the set)
            return $this->$name;
        default:
            throw new \Exception("Property $name doesn't exist.");
            break;
    }
}
J-Rou
fonte
2
@ krzysztof-przygoda: Este "Método Mágico" sempre tem um preço. Eles precisam usar recursão property_exists(get_class($this), $name)e a recursão é lenta. Existe uma maneira de atenuar isso com o cache, mas ainda será mais lento do que criar os getters e os setters manualmente. Eu apenas escrevi isso como uma alternativa. Na verdade, eu não recomendo o uso de "Métodos Mágicos". O tempo extra de criação de getters e setters geralmente é insignificante.
J-Rou
7

Além das respostas já excelentes e respeitadas aqui, eu gostaria de expandir o PHP sem setters / getters.

O PHP não possui sintaxe getter e setter . Ele fornecemétodossubclassificados ou mágicos para permitir "ligar" e substituir o processo de pesquisa de propriedades, conforme apontado por Dave .

O Magic permite que programadores preguiçosos façam mais com menos código em um momento em que estamos ativamente envolvidos em um projeto e o conheçam intimamente, mas geralmente à custa da legibilidade.

Desempenho Todas as funções desnecessárias, resultantes da imposição de uma arquitetura de código do tipo getter / setter no PHP, envolvem seu próprio quadro de pilha de memória após a chamada e estão desperdiçando ciclos da CPU.

Legibilidade: A base de código incorre em linhas de código inchadas, o que afeta a navegação de código, pois mais LOC significa mais rolagem.

Preferência: pessoalmente, como regra geral, tomo o fracasso da análise de código estático como um sinal para evitar seguir o caminho mágico, desde que os óbvios benefícios a longo prazo me escapem naquele momento.

Falácias:

Um argumento comum é legibilidade. Por exemplo, $someobject->widthé mais fácil ler do que $someobject->width(). No entanto, ao contrário do planetacircumference ou width, que pode ser assumido static, a instância de um objeto como $someobject, que requer uma função de largura, provavelmente faz uma medição da largura da instância do objeto.
Portanto, a legibilidade aumenta principalmente devido a esquemas de nomeação assertivos e não ocultando a função que gera um determinado valor de propriedade.

__get / __set usa:

  • pré-validação e pré-saneamento de valores de propriedades

  • strings eg

    "
    some {mathsobj1->generatelatex} multi
    line text {mathsobj1->latexoutput}
    with lots of variables for {mathsobj1->generatelatex}
     some reason
    "

    Nesse caso generatelatex seguiria um esquema de nomeação de actionname + methodname

  • casos especiais e óbvios

    $dnastringobj->homeobox($one_rememberable_parameter)->gattaca->findrelated()
    $dnastringobj->homeobox($one_rememberable_parameter)->gttccaatttga->findrelated()

Nota: O PHP optou por não implementar a sintaxe getter / setter. Não estou afirmando que getters / setter são geralmente ruins.

Lorenz Lo Sauer
fonte
6
class MyClass {
    private $firstField;
    private $secondField;
    private $thirdField;

    public function __get( $name ) {
        if( method_exists( $this , $method = ( 'get' . ucfirst( $name  ) ) ) )
            return $this->$method();
        else
            throw new Exception( 'Can\'t get property ' . $name );
    }

    public function __set( $name , $value ) {
        if( method_exists( $this , $method = ( 'set' . ucfirst( $name  ) ) ) )
            return $this->$method( $value );
        else
            throw new Exception( 'Can\'t set property ' . $name );
    }

    public function __isset( $name )
    {
        return method_exists( $this , 'get' . ucfirst( $name  ) ) 
            || method_exists( $this , 'set' . ucfirst( $name  ) );
    }

    public function getFirstField() {
        return $this->firstField;
    }

    protected function setFirstField($x) {
        $this->firstField = $x;
    }

    private function getSecondField() {
        return $this->secondField;
    }
}

$obj = new MyClass();

echo $obj->firstField; // works
$obj->firstField = 'value'; // works

echo $obj->getFirstField(); // works
$obj->setFirstField( 'value' ); // not works, method is protected

echo $obj->secondField; // works
echo $obj->getSecondField(); // not works, method is private

$obj->secondField = 'value'; // not works, setter not exists

echo $obj->thirdField; // not works, property not exists

isset( $obj->firstField ); // returns true
isset( $obj->secondField ); // returns true
isset( $obj->thirdField ); // returns false

Pronto!

joas
fonte
Muito clichê. Imagine essas coisas em todas as classes. Evite o IMO #
DarkNeuron
O PHP não suporta getters e setters pelos mesmos motivos que você menciona. Qualquer implementação desse tipo afeta severamente o desempenho do script do lado do servidor.
JOAS
Eu acho que isso vai contra propriedades 'privadas'. Você os encapsula, mas também permite acessar diretamente.
Koray Küpe 18/03/19
@ KorayKüpe apenas se o getter estiver definido. Eu uso muito esse encapsulamento (com muitas melhorias) e funciona perfeitamente. Você também pode estender a classe e usá-la em todo o código facilmente.
Joas
5

Bem, PHP tem métodos mágicos __get, __set, __issete __unset, o que é sempre um começo. Infelizmente, as propriedades OO apropriadas são mais do que métodos mágicos. O principal problema com a implementação do PHP é que métodos mágicos são chamados para todas as propriedades inacessíveis. O que significa que você deve se repetir (por exemplo, chamando property_exists ()) nos métodos mágicos ao determinar se o nome é realmente uma propriedade do seu objeto. E você realmente não pode resolver esse problema geral com uma classe base, a menos que todas as suas classes herdem ie. ClassWithProperties, já que o PHP não possui herança múltipla.

Por outro lado, as novas classes de estilos do Python oferecem a você property(), o que permite definir explicitamente todas as suas propriedades. C # tem sintaxe especial.

http://en.wikipedia.org/wiki/Property_(programming)

Emanuel Landeholm
fonte
1
Chamar property_exists, class_vars ou array_key_exists (ou seja, verificar se a propriedade realmente existe) é apenas uma etapa para evitar um erro fatal no tempo de execução. Não sei se não ser explícito é o mesmo que ser repetitivo na codificação.
Davis Peixoto
1
Justo. Mas em Python e C # essa repetição não é necessária. Eu acho que isso é uma força.
Emanuel Landeholm
4

Fiz um experimento usando o método mágico __call. Não tenho certeza se devo publicá-lo (por causa de todos os avisos "NÃO USAR MÉTODOS MÁGICOS" nas outras respostas e comentários), mas vou deixá-lo aqui .. apenas no caso de alguém achar útil.


public function __call($_name, $_arguments){
    $action  = substr($_name, 0, 4);
    $varName = substr($_name, 4);

    if (isset($this->{$varName})){
        if ($action === "get_") return $this->{$varName};
        if ($action === "set_") $this->{$varName} = $_arguments[0];
    }
}

Basta adicionar esse método acima em sua classe, agora você pode digitar:

class MyClass{
    private foo = "bar";
    private bom = "bim";
    // ...
    // public function __call(){ ... }
    // ...
}
$C = new MyClass();

// as getter
$C->get_foo(); // return "bar"
$C->get_bom(); // return "bim"

// as setter
$C->set_foo("abc"); // set "abc" as new value of foo
$C->set_bom("zam"); // set "zam" as new value of bom


Dessa forma, você pode obter / definir tudo em sua classe, se existir, se precisar apenas de alguns elementos específicos, poderá usar uma "lista de permissões" como filtro.

Exemplo:

private $callWhiteList = array(
    "foo" => "foo",
    "fee" => "fee",
    // ...
);

public function __call($_name, $_arguments){
    $action  = substr($_name, 0, 4);
    $varName = $this->callWhiteList[substr($_name, 4)];

    if (!is_null($varName) && isset($this->{$varName})){
        if ($action === "get_") return $this->{$varName};
        if ($action === "set_") $this->{$varName} = $_arguments[0];
    }
}

Agora você só pode obter / definir "foo" e "fee".
Você também pode usar essa "lista de permissões" para atribuir nomes personalizados para acessar seus vars.
Por exemplo,

private $callWhiteList = array(
    "myfoo" => "foo",
    "zim" => "bom",
    // ...
);

Com essa lista, agora você pode digitar:

class MyClass{
    private foo = "bar";
    private bom = "bim";
    // ...
    // private $callWhiteList = array( ... )
    // public function __call(){ ... }
    // ...
}
$C = new MyClass();

// as getter
$C->get_myfoo(); // return "bar"
$C->get_zim(); // return "bim"

// as setter
$C->set_myfoo("abc"); // set "abc" as new value of foo
$C->set_zim("zam"); // set "zam" as new value of bom

.
.
.
Isso é tudo.


Doc: __call () é acionado ao chamar métodos inacessíveis em um contexto de objeto.

Sabaz
fonte
O problema com todas essas soluções "mágicas" é que elas simplesmente usam esses métodos mágicos porque estão lá e são úteis porque o problema solicitado é simples e genérico. Depois de sair desse nível de problema genérico, você encontrará requisitos específicos que não podem ser resolvidos por um método mágico simples, mas exigiriam um método mágico muito complexo - ou setters e getters codificados individuais.
Sven
2

Depois de ler os outros conselhos, estou inclinado a dizer o seguinte:

Como regra GENERIC , você nem sempre definirá setters para TODAS as propriedades, especialmente as "internas" (semáforos, sinalizadores internos ...). As propriedades somente leitura não terão setters, obviamente, portanto, algumas propriedades terão apenas getters; é aí que __get () reduz o código:

  • defina um __get () (getters globais mágicos) para todas as propriedades semelhantes,
  • agrupe-os em matrizes para:
    • eles compartilharão características comuns: valores monetários poderão / serão apresentados corretamente formatados, datas em um layout específico (ISO, EUA, Internacional), etc.
    • o próprio código pode verificar se apenas as propriedades permitidas e existentes estão sendo lidas usando esse método mágico.
    • sempre que precisar criar uma nova propriedade semelhante, apenas a declare e inclua seu nome na matriz apropriada e pronto. É muito mais RÁPIDO do que definir um novo getter, talvez com algumas linhas de código repetidas repetidamente em todo o código da classe.

Sim! também poderíamos escrever um método privado para fazer isso, mas, novamente, teremos MUITOS métodos declarados (memória ++) que acabam chamando outro método, sempre o mesmo. Por que simplesmente não escrever um método ÚNICO para governá-los todos ...? [Sim! trocadilho absolutamente pretendido! :)]

Os setters mágicos também podem responder SOMENTE a propriedades específicas, para que todas as propriedades do tipo de data possam ser rastreadas em relação a valores inválidos em um único método. Se as propriedades do tipo de data foram listadas em uma matriz, seus setters podem ser definidos facilmente. Apenas um exemplo, é claro. há muitas situações.

Sobre legibilidade ... Bem ... Esse é outro debate: eu não gosto de estar vinculado aos usos de um IDE (na verdade, eu não os uso, eles tendem a me dizer (e me forçar ) como escreva ... e eu gosto de codificar "beleza"). Eu costumo ser consistente em nomear, portanto, usar ctags e algumas outras ajudas é suficiente para mim ... Enfim: depois que todos esses setters e getters mágicos terminarem, escrevo os outros setters que são específicos demais ou "especiais" para ser generalizado em um método __set (). E isso abrange tudo o que preciso sobre como obter e definir propriedades. É claro: nem sempre existe um terreno comum, ou existem poucas propriedades que não valem a pena codificar um método mágico, e ainda há o bom e tradicional par tradicional de setter / getter.

Linguagens de programação são exatamente isso: linguagens artificiais humanas. Então, cada um deles tem sua própria entonação ou sotaque, sintaxe e sabor, então não pretendo escrever um código Ruby ou Python usando o mesmo "sotaque" que Java ou C #, nem escreveria um JavaScript ou PHP para se parecer Perl ou SQL ... Use-os da maneira como devem ser usados.

Manuel
fonte
1

De um modo geral, a primeira maneira é mais popular em geral, porque aqueles com conhecimento prévio em programação podem facilmente fazer a transição para PHP e realizar o trabalho de maneira orientada a objetos. A primeira maneira é mais universal. Meu conselho seria seguir o que é experimentado e verdadeiro em muitos idiomas. Então, quando e se você usar outro idioma, estará pronto para realizar alguma coisa (em vez de gastar tempo reinventando a roda ).

Anthony Rutledge
fonte
0

Existem várias maneiras de criar código-fonte em uma convenção de netbeans. Isso é legal. Isso torna os pensamentos mais fáceis === FALSE. Basta usar o tradicional, especialmente se você não tiver certeza de qual das propriedades deve ser encapsulada e qual não. Eu sei, é um código boi .... pla ..., mas para trabalhos de depuração e muitos outros acha que é o caminho melhor e mais claro. Não gaste muito tempo com milhares de artes como criar getters e setters simples. Você não pode implementar também alguns padrões de design, como a regra do deímetro e assim por diante, se você usar magics. Em situações específicas, você pode usar magic_calls ou para soluções pequenas, rápidas e claras. Claro que você também pode criar soluções para padrões de design dessa maneira, mas por que torná-lo mais difícil de viver.

Dennis Komnenovic
fonte
0

Validando + Formatação / Derivação de Valores

Setters permitem validar dados e getters permitem formatar ou derivar dados. Os objetos permitem que você encapsule dados e seu código de validação e formatação em um pacote puro que incentive o DRY.

Por exemplo, considere a seguinte classe simples que contém uma data de nascimento.

class BirthDate {

    private $birth_date;

    public function getBirthDate($format='Y-m-d') {
        //format $birth_date ...
        //$birth_date = ...
        return $birth_date;
    }

    public function setBirthDate($birth_date) {                   
        //if($birth_date is not valid) throw an exception ...          
        $this->birth_date = $birth_date;
    }

    public function getAge() {
        //calculate age ...
        return $age;
    }

    public function getDaysUntilBirthday() {
        //calculate days until birth days
        return $days;
    }
}

Você deseja validar que o valor que está sendo definido é

  • Uma data válida
  • Não no futuro

E você não deseja fazer essa validação em todo o seu aplicativo (ou em vários aplicativos). Em vez disso, é mais fácil tornar a variável membro protegida ou privada (para tornar o levantador o único ponto de acesso) e validar no levantador, porque você saberá que o objeto contém uma data de nascimento válida, independentemente da parte do aplicativo de origem do objeto e, se você quiser adicionar mais validação, poderá adicioná-lo em um único local.

Você pode querer adicionar vários formatadores que operam no mesmo ie variável de membro getAge()e getDaysUntilBirthday()e você pode querer impor um formato configurável em getBirthDate()acordo com a localidade. Portanto, eu prefiro acessar valores consistentemente através de getters, em vez de misturar $date->getAge()com$date->birth_date .

getters e setters também são úteis quando você estende objetos. Por exemplo, suponha que seu aplicativo seja necessário para permitir datas de nascimento de mais de 150 anos em alguns lugares, mas não em outros. Uma maneira de resolver o problema sem repetir qualquer código seria estender o BirthDateobjeto e colocar a validação adicional no setter.

class LivingBirthDate extends BirthDate {

    public function setBirthDate($birth_date) {
        //if $birth_date is greater than 150 years throw an exception
        //else pass to parent's setter
        return parent::setBirthDate($birth_date);
    }
}
FuzzyTree
fonte
No entanto, muitas vezes você precisa validar propriedades juntas (e não apenas individualmente). Eu acho que permitir "setters" significa que você também não está capturando contexto. A validação deve ser feita contextualmente. Além disso, você será forçado a verificar algum sinalizador "isValid" em todos os métodos que você possui (e executar a validação se for falso). Dito isto, os criadores de conteúdo fornecem uma maneira útil de digitar dicas, como quando você tem uma propriedade que deseja ser um Objeto de Valor (ou seja, Dinheiro).
prograhammer
Não entendo o que você quer dizer com ser forçado a verificar um sinalizador "isValid"? Se a única maneira de definir valores é através de setters que executam a validação, você sabe que os dados são válidos pelo fato de que foram definidos com êxito. Se você precisar validar propriedades juntos, poderá escrever um método de validação comum que os setters dessas propriedades chamam.
FuzzyTree
Digamos que você tenha uma classe de funcionários com setHirede setHireDate. Não é válido permitir que alguém defina uma data de contratação sem também definir o funcionário como contratado. Mas não há como você aplicar isso. Se você aplicá-lo em um desses setters, está forçando a ordem da "configuração" e isso exige mais leitura de código de um desenvolvedor para saber. Então, quando você adota um método como $employee->promote($newPosition);o de verificar uma sinalização para ver se a validação foi feita ou assume que não foi feita e a executa novamente (redundante).
prograhammer
Em vez disso, capture as interações. Talvez $employee->updateWorkStatus($hired, $hireDate);ou se mais avançado $employee->adminUpdate(\Employee\AdminUpdateDTO $dto);. Agora você pode validar no contexto necessário e decidir se é necessária alguma validação extra.
prograhammer
updateWorkStatus é essencialmente uma função setter que define 2 em vez de 1, mas o conceito é o mesmo. Essa é uma maneira de fazer isso, mas você também pode colocar a validação contextual em um método comum que é executado apenas quando todas as propriedades que precisam ser validadas juntas estiverem definidas, ou seja, a parte contextual da validação seria chamada por setHiredDate e setHired, mas seria executada apenas se o isset contratado e o isset hiredDate fossem verdadeiros.
FuzzyTree
0

Este post não é especificamente sobre __gete __setsim __callque é a mesma idéia, exceto para chamadas de método. Como regra geral, eu me afasto de qualquer tipo de método mágico que permita sobrecarga por motivos descritos nos comentários e postagens , NO ENTANTO , recentemente, deparei-me com uma API de terceiros que utilizo, que usa um SERVICE e um SUB-SERVICE, por exemplo :

http://3rdparty.api.com?service=APIService.doActionOne&apikey=12341234

A parte importante disso é que essa API tem tudo a mesma coisa, exceto a sub-ação, neste caso doActionOne. A ideia é que o desenvolvedor (eu e outros usuários dessa classe) possa chamar o sub-serviço pelo nome, em vez de algo como:

$myClass->doAction(array('service'=>'doActionOne','args'=>$args));

Eu poderia fazer:

 $myClass->doActionOne($args);

Para codificar isso seria apenas muita duplicação (este exemplo se parece muito com o código):

public function doActionOne($array)
    {
        $this->args     =   $array;
        $name           =   __FUNCTION__;
        $this->response =   $this->executeCoreCall("APIService.{$name}");
    }

public function doActionTwo($array)
    {
        $this->args     =   $array;
        $name           =   __FUNCTION__;
        $this->response =   $this->executeCoreCall("APIService.{$name}");
    }

public function doActionThree($array)
    {
        $this->args     =   $array;
        $name           =   __FUNCTION__;
        $this->response =   $this->executeCoreCall("APIService.{$name}");
    }

protected function executeCoreCall($service)
    {
        $cURL = new \cURL();
        return $cURL->('http://3rdparty.api.com?service='.$service.'&apikey='.$this->api.'&'.http_build_query($this->args))
                    ->getResponse();
    }

Mas com o método mágico de __call()eu sou capaz de acessar todos os serviços com métodos dinâmicos:

public function __call($name, $arguments)
    {
        $this->args     =   $arguments;
        $this->response =   $this->executeCoreCall("APIService.{$name}");   
        return $this;
    }

O benefício dessa chamada dinâmica para o retorno de dados é que, se o fornecedor adicionar outro sub-serviço, não preciso adicionar outro método à classe ou criar uma classe estendida etc. Não tenho certeza se isso é útil. ninguém, mas eu percebi que eu iria mostrar um exemplo onde __set, __get, __call, etc. pode ser uma opção para a consideração já que a função principal é o retorno de dados.


EDITAR:

Coincidentemente, vi isso alguns dias após a publicação, descrevendo exatamente o meu cenário. Não é a API à qual eu estava me referindo, mas a aplicação dos métodos é idêntica:

Estou usando a API corretamente?

Rasclatt
fonte
-2

Atualização: Não use esta resposta, pois esse é um código muito idiota que eu encontrei enquanto aprendia. Basta usar getter e setter simples, é muito melhor.


Normalmente, eu uso esse nome de variável como nome da função e adiciono parâmetro opcional a essa função para que, quando esse parâmetro opcional for preenchido pelo chamador, defina-o para a propriedade e retorne $ this object (encadeamento) e, em seguida, quando esse parâmetro opcional não especificado por chamador, eu apenas retorno a propriedade ao chamador.

Meu exemplo:

class Model
{
     private $propOne;
     private $propTwo;

     public function propOne($propVal = '')
     {
          if ($propVal === '') {
              return $this->propOne;
          } else {
              $this->propOne = $propVal;
              return $this;
          }
     }

     public function propTwo($propVal = '')
     {
          if ($propVal === '') {
              return $this->propTwo;
          } else {
              $this->propTwo = $propVal;
              return $this;
          }
     }
}
ajiyakin
fonte
Agora a pergunta permanece: como você define uma propriedade para a string vazia? E como você detecta que a configuração de uma propriedade para a cadeia vazia realmente falhou e funcionou como um getter? Pense nos formulários HTML que enviam campos vazios como seqüências de caracteres ... E não: o uso de um valor diferente como NULL como valor padrão não resolve o problema.
Sven