Getter y Setter?

203

No soy un desarrollador de PHP, por lo que me pregunto si en PHP es más popular usar getter / setters explícitos, en un estilo OOP puro, con campos privados (como a mí me gusta):

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;
    }
}

o solo campos públicos:

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

Gracias

marca
fuente
77
Después de probar un código de las respuestas, usé el código que estás usando en la pregunta. Qué triste :-(
sumid
9
PHPstorm ... generate> getters y setters. == win
DevDonkey
@DevDonkey No es una victoria en absoluto. Para mantener datos estructurados, use matrices en su lugar. @: Mark Esto no es para lo que son o son los objetos. Getters y setters son malvados: yegor256.com/2014/09/16/getters-and-setters-are-evil.html
Kubo2

Respuestas:

222

Puedes usar métodos mágicos __get y php__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
fuente
15
Creo que quieres decir __gety __set. Hay dos guiones bajos, no uno. Aquí está el enlace directo a la parte derecha de la página: php.net/manual/en/… (+1 para una respuesta correcta)
Computerish
28
¿Cuál es el beneficio contra las publicpropiedades, si no hay validación / saneamiento?
KingCrunch
77
@ KingCrunch, esto es solo un ejemplo. Un muy, muy falso ejemplo para un recurso poderoso.
Davis Peixoto
10
Eso no es realmente setter y getter. ¡Normalmente necesito para cada propiedad una implementación diferente de getter!
Sumid
79
No lo haga: con métodos mágicos PERDERÁ casi todas las características relacionadas con la calidad, en muchos IDE (incluso vim): autocompletado, herencia explícita de PHP, interpretación rápida de PHP y generación y salida útil de PHPDoc. cf. stackoverflow.com/a/6184893/490589
Ronan
113

¿Por qué usar getters y setters?

  1. Escalabilidad : es más fácil refactorizar un getter que buscar todas las asignaciones var en un código de proyecto.
  2. Depuración : puede poner puntos de interrupción en setters y getters.
  3. Más limpio : las funciones mágicas no son una buena solución para escribir menos, su IDE no le sugerirá el código. Mejor uso de plantillas para captadores de escritura rápida.

asignación directa y captadores / setters

Wiliam
fuente
77
Si usa @property, su IDE le sugerirá el código (probado con PhpStorm 7)
Alex2php
41

Google ya publicó una guía sobre la optimización de PHP y la conclusión fue:

Sin getter y setter Optimizando PHP

Y no, no debes usar métodos mágicos . Para PHP, los métodos mágicos son malos. ¿Por qué?

  1. Son difíciles de depurar.
  2. Hay un impacto negativo en el rendimiento.
  3. Requieren escribir más código.

PHP no es Java, C ++ o C #. PHP es diferente y juega con diferentes roles.

magallanes
fuente
10
Tiendo a estar de acuerdo con esa idea; eso $dog->name = 'fido'es mejor que $dog->setName('fido'). Cuando realmente mute una propiedad (por ejemplo: $dog->increaseAge(1)puedo construir el método que hace la validación necesaria y muta esa propiedad. Pero no todas las acciones realmente requieren mutación en ese sentido.
Charlie Schliesser
11
El artículo no dice " no lo hagas ", dice "setters y getters ingenuos".
Brett Santore
13
Es seguro asumir que un artículo escrito por Google que tiene el título "Consejos de rendimiento de PHP" NO pretende sugerir un buen estilo de codificación, sino una ejecución rápida del código. El capítulo que trata sobre setters y getters se etiqueta "Evita escribir setters y getters ingenuos", y el ejemplo de código es exactamente eso: ingenuo. Establece y obtiene solo una variable sin ninguna validación. Este tipo de setter / getter es inútil. Hacer la validación dentro de un setter (simplemente use una sugerencia de tipo para el argumento del método) hará que los setters / getters sean útiles porque ahora su código SABE a qué se refiere.
Sven
3
Esto es como decir que el estilo en línea es mejor. Por supuesto, el rendimiento es mejor, pero ¿es mejor el código? No sabía que los ingenieros de Google usaran php de todos modos
Claudiu Creanga
13

La encapsulación es importante en cualquier lenguaje OO, la popularidad no tiene nada que ver con eso. En lenguajes de tipo dinámico, como PHP, es especialmente útil porque hay pocas formas de garantizar que una propiedad sea de un tipo específico sin usar setters.

En PHP, esto funciona:

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

En Java, no:

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

El uso de métodos mágicos ( __gety __set) también funciona, pero solo cuando se accede a una propiedad que tiene una visibilidad inferior a la que puede acceder el alcance actual. Puede causarle dolores de cabeza fácilmente cuando intenta depurar, si no se usa correctamente.

netcoder
fuente
77
Getters y setter no traen encapsulación. Encapsulación == objetos hacen algo con sus propios datos en lugar de darlos afuera. Getters y setters no son una herramienta para forzar la escritura en lenguajes de escritura dinámica como PHP.
smentek
14
@smentek: Claramente te falta al menos la mitad de lo que realmente es la encapsulación.
netcoder
2
Como una actualización de esto para cualquiera que busque, PHP 7.4 vendrá con soporte de propiedad escrita. Entonces podría declarar $barcomo inten el primer ejemplo: wiki.php.net/rfc/typed_properties_v2
Kevin
7

Si prefiere usar la función __call, puede usar este método. Funciona con

  • OBTENER => $this->property()
  • SET => $this->property($value)
  • OBTENER => $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
fuente
2
@ krzysztof-przygoda: estos "métodos mágicos" siempre tienen un precio. Tienen que usar la recursividad property_exists(get_class($this), $name)y la recursividad es lenta. Hay una manera de mitigar esto con el almacenamiento en caché, pero aún será más lento que crear los captadores y establecedores a mano. Solo escribí esto como una alternativa. En realidad no recomiendo usar "Métodos mágicos". El tiempo extra de crear los captadores y establecedores suele ser insignificante.
J-Rou
7

Además de las respuestas ya excelentes y respetadas aquí, me gustaría expandirme en PHP que no tiene setters / getters.

PHP no tiene sintaxis getter y setter . Proporcionamétodossubclases o mágicos para permitir "enganchar" y anular el proceso de búsqueda de propiedades, como señaló Dave .

Magic nos permite a los programadores perezosos hacer más con menos código en un momento en el que participamos activamente en un proyecto y lo conocemos íntimamente, pero generalmente a expensas de la legibilidad.

Rendimiento Cada función innecesaria, que resulta de forzar una arquitectura de código tipo getter / setter en PHP, involucra su propio marco de pila de memoria al invocarlo y está desperdiciando ciclos de CPU.

Legibilidad: la base de código incurre en líneas de código hinchadas, lo que afecta la navegación de código, ya que más LOC significa más desplazamiento.

Preferencia: Personalmente, como regla general, tomo la falla del análisis de código estático como una señal para evitar seguir el camino mágico siempre que los obvios beneficios a largo plazo se me escapen en ese momento.

Falacias:

Un argumento común es la legibilidad. Por ejemplo, eso $someobject->widthes más fácil de leer que $someobject->width(). Sin embargo, a diferencia de un planeta circumferenceo width, que se puede suponer que es static, la instancia de un objeto como $someobject, que requiere una función de ancho, probablemente tome una medida del ancho de la instancia del objeto.
Por lo tanto, la legibilidad aumenta principalmente debido a esquemas de nombres asertivos y no al ocultar la función que genera un valor de propiedad dado.

__get / __set utiliza:

  • prevalidación y pre-saneamiento de valores de propiedad

  • cadenas por ejemplo

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

    En este caso generatelatexse adheriría a un esquema de nombres de actionname + methodname

  • casos especiales y obvios

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

Nota: PHP eligió no implementar la sintaxis getter / setter. No estoy afirmando que getters / setter sean generalmente malos.

Lorenz Lo Sauer
fuente
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

¡Listo!

joas
fuente
Demasiado repetitivo. Imagina que estas cosas están en cada clase. Evitar la OMI
DarkNeuron
PHP no admite getters y setters por las mismas razones que mencionas. Cualquier implementación de este tipo afecta severamente el rendimiento del script del lado del servidor.
joas
Creo que esto va en contra de las propiedades 'privadas'. Los encapsula, pero también permite acceder directamente.
Koray Küpe
@ KorayKüpe solo si el getter está definido. Utilizo mucho esta encapsulación (con muchas mejoras) y funciona perfectamente. También puede extender la clase y usarla en todo el código fácilmente.
joas
5

Bueno, PHP tiene métodos mágicos __get, __set, __issety __unset, lo que es siempre un comienzo. Por desgracia, las propiedades de OO (¿entiendes?) Son más que métodos mágicos. El principal problema con la implementación de PHP es que se requieren métodos mágicos para todas las propiedades inaccesibles. Lo que significa que debe repetirse (por ejemplo, llamando a property_exists ()) en los métodos mágicos al determinar si el nombre es realmente una propiedad de su objeto. Y realmente no puede resolver este problema general con una clase base a menos que todas sus clases hereden de ie. ClassWithProperties, ya que PHP carece de herencia múltiple.

Por el contrario, Python le ofrece nuevas clases de estilo property(), que le permiten definir explícitamente todas sus propiedades. C # tiene una sintaxis especial.

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

Emanuel Landeholm
fuente
1
Llamar a property_exists, class_vars o array_key_exists (es decir, verificar si la propiedad realmente existe) es solo un paso para evitar un error fatal en tiempo de ejecución. No estoy seguro de si no ser displicente es lo mismo que ser repetitivo en la codificación.
Davis Peixoto
1
Lo suficientemente justo. Pero en Python y C # esta repetición no es necesaria. Creo que eso es una fortaleza.
Emanuel Landeholm
4

Hice un experimento usando el método mágico __call. No estoy seguro de si debería publicarlo (debido a todas las advertencias de "NO UTILIZAR MÉTODOS MÁGICOS" en las otras respuestas y comentarios) pero lo dejaré aquí ... en caso de que alguien lo encuentre ú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];
    }
}

Simplemente agregue ese método arriba en su clase, ahora puede escribir:

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


De esta manera, puede obtener / configurar todo en su clase si existe, si lo necesita solo para unos pocos elementos específicos, puede usar una "lista blanca" como filtro.

Ejemplo:

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];
    }
}

Ahora solo puede obtener / configurar "foo" y "fee".
También puede usar esa "lista blanca" para asignar nombres personalizados para acceder a sus variables.
Por ejemplo,

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

Con esa lista ahora puede escribir:

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

.
.
.
Eso es todo.


Doc: __call () se activa al invocar métodos inaccesibles en un contexto de objeto.

Sabaz
fuente
El problema con todas estas soluciones "mágicas" es que simplemente usan estos métodos mágicos porque están allí, y son útiles porque el problema planteado es simple y genérico. Una vez que abandone este nivel de problema genérico, encontrará requisitos específicos que no se pueden resolver con un método mágico simple, pero que requerirían un método mágico muy complejo, o establecedores y captadores individuales codificados.
Sven
2

Después de leer los otros consejos, me inclino a decir que:

Como regla GENÉRICA , no siempre definirá definidores para TODAS las propiedades, especialmente las "internas" (semáforos, marcas internas ...). Las propiedades de solo lectura no tendrán setters, obviamente, por lo que algunas propiedades solo tendrán getters; ahí es donde __get () llega a reducir el código:

  • defina un __get () (captadores globales mágicos) para todas esas propiedades que son similares,
  • agrúpelos en matrices para que:
    • compartirán características comunes: los valores monetarios aparecerán / pueden formatearse correctamente, las fechas en un diseño específico (ISO, EE. UU., Intl.), etc.
    • el código en sí mismo puede verificar que solo las propiedades existentes y permitidas se lean utilizando este método mágico.
    • cada vez que necesite crear una nueva propiedad similar, simplemente declare y agregue su nombre a la matriz adecuada y listo. Eso es MÁS RÁPIDO que definir un nuevo captador, tal vez con algunas líneas de código REPETIDAS una y otra vez en todo el código de la clase.

¡Si! podríamos escribir un método privado para hacer eso, también, pero de nuevo, tendremos MUCHOS métodos declarados (memoria ++) que terminan llamando a otro método, siempre el mismo. ¿Por qué no escribir una SOLA método para gobernarlos a todos ...? [¡Sí! juego de palabras absolutamente previsto! :)]

Los establecedores de magia también pueden responder SOLAMENTE a propiedades específicas, por lo que todas las propiedades de tipo de fecha se pueden seleccionar contra valores no válidos en un solo método. Si las propiedades de tipo de fecha se enumeran en una matriz, sus definidores se pueden definir fácilmente. Solo un ejemplo, por supuesto. Hay demasiadas situaciones.

Sobre la legibilidad ... Bueno ... Eso es otro debate: no me gusta estar vinculado a los usos de un IDE (de hecho, yo no uso de ellos, tienden a decirme (y obligar a mí) cómo escribir ... y tengo mis gustos sobre la codificación de "belleza"). Tiendo a ser coherente con los nombres, por lo que usar ctags y un par de otras ayudas es suficiente para mí ... De todos modos: una vez que todos estos setters y getters mágicos están listos, escribo los otros setters que son demasiado específicos o "especiales" para se generalizará en un método __set (). Y eso cubre todo lo que necesito para obtener y configurar propiedades. Por supuesto: no siempre hay un terreno en común, o hay unas pocas propiedades que no merecen la molestia de codificar un método mágico, y luego sigue existiendo el viejo buen setter / getter tradicional.

Los lenguajes de programación son solo eso: lenguajes artificiales humanos. Entonces, cada uno de ellos tiene su propia entonación o acento, sintaxis y sabor, por lo que no pretendo escribir un código Ruby o Python usando el mismo "acento" que Java o C #, ni escribiría un JavaScript o PHP para parecerse Perl o SQL ... Úselos de la forma en que están destinados a ser utilizados.

Manuel
fuente
1

En términos generales, la primera forma es más popular en general porque aquellos con conocimientos previos de programación pueden fácilmente pasar a PHP y realizar el trabajo de manera orientada a objetos. La primera forma es más universal. Mi consejo sería seguir con lo que se prueba y es verdadero en muchos idiomas. Luego, cuando y si usa otro idioma, estará listo para lograr algo (en lugar de perder tiempo reinventando la rueda ).

Anthony Rutledge
fuente
0

Hay muchas formas de crear código fuente en una convención netbeans. Esto es bonito. Hace pensar que es más fácil === FALSO. Simplemente use el tradicional, especialmente si no está seguro de cuál de las propiedades debe encapsularse y cuál no. Lo sé, es un código boi .... pla ..., pero para trabajos de depuración y muchos otros piensan que es la mejor manera, clara. No pase mucho tiempo con miles de artes cómo hacer captadores y colocadores simples. No puede implementar también algunos patrones de diseño como la regla demeter y así sucesivamente, si usa magia. En una situación específica, puede usar magic_calls o para soluciones pequeñas, rápidas y claras. Claro que también podría hacer soluciones para patrones de diseño de esta manera, pero por qué hacer que su vida sea más difícil.

Dennis Komnenovic
fuente
0

Validar + formatear / derivar valores

Los setters le permiten validar datos y los getters le permiten formatear o derivar datos. Los objetos le permiten encapsular datos y su código de validación y formato en un paquete ordenado que fomenta DRY.

Por ejemplo, considere la siguiente clase simple que contiene una fecha de nacimiento.

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;
    }
}

Deberá validar que el valor establecido sea

  • Una fecha valida
  • No en el futuro

Y no desea hacer esta validación en toda su aplicación (o en múltiples aplicaciones para el caso). En cambio, es más fácil hacer que la variable miembro esté protegida o privada (para que el configurador sea el único punto de acceso) y validar en el configurador porque entonces sabrá que el objeto contiene una fecha de nacimiento válida, sin importar qué parte del aplicación del objeto proviene y si desea agregar más validación, puede agregarlo en un solo lugar.

Es posible que desee agregar varios formateadores que operan en la misma, es decir variable miembro getAge()y getDaysUntilBirthday()y es posible que desee hacer cumplir un formato configurable getBirthDate()según la zona. Por lo tanto, prefiero el acceso consistentemente valores a través de captadores en lugar de mezclar $date->getAge()con $date->birth_date.

getters y setters también son útiles cuando extiendes objetos. Por ejemplo, suponga que su solicitud necesita permitir fechas de nacimiento de más de 150 años en algunos lugares pero no en otros. Una forma de resolver el problema sin repetir ningún código sería extender el BirthDateobjeto y colocar la validación adicional en el 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
fuente
Sin embargo, muchas veces necesita validar propiedades juntas (y no solo individualmente). Creo que permitir "setters" significa que tampoco estás capturando contexto. La validación debe hacerse de forma contextual. Además, se verá obligado a verificar alguna marca "isValid" en cada método que tenga (y validar si es falso). Dicho esto, los establecedores proporcionan una forma útil de sugerencia de tipo, como cuando tiene una propiedad que desea ser un Objeto de valor (es decir, Dinero).
prograhammer
¿No entiendo a qué te refieres cuando te obligan a marcar una bandera "es Válida"? Si la única forma de establecer valores es a través de establecedores que realizan la validación, entonces usted sabe que los datos son válidos por el hecho de que se establecieron correctamente. Si necesita validar propiedades juntas, puede escribir un método de validación común al que llaman los establecedores de esas propiedades.
FuzzyTree
Digamos que tiene una clase de empleado con setHiredy setHireDate. No es válido permitir que alguien establezca una fecha de contratación sin también establecer al empleado como contratado. Pero no hay forma de que hagas cumplir esto. Si lo aplica en uno de estos configuradores, entonces está forzando el orden de "configuración", y eso requiere más lectura de código de un desarrollador para saberlo. Luego, cuando vaya a hacer un método como $employee->promote($newPosition);, debe verificar una marca para ver si se realizó la validación o asumir que no se ha hecho y volver a hacerlo (redundante).
prograhammer
En cambio, captura las interacciones. Quizás $employee->updateWorkStatus($hired, $hireDate);o si más avanzado $employee->adminUpdate(\Employee\AdminUpdateDTO $dto);. Ahora puede validar en el contexto que necesita y decidir si se necesita alguna validación adicional.
prograhammer
updateWorkStatus es esencialmente una función de establecimiento que establece 2 en lugar de 1 valor, pero el concepto es el mismo. Esa es una forma de hacerlo, pero también puede poner la validación contextual en un método común que solo se ejecuta cuando se establecen todas las propiedades que deben validarse juntas, es decir, la parte contextual de la validación se llamaría tanto por setHiredDate como por setHired, pero solo se ejecutaría si tanto isset contratado como isset hiredDate eran verdaderos.
FuzzyTree
0

Este post no es específicamente sobre __gety __setsino __callque es la misma idea, excepto para llamadas de método. Como regla general, me mantengo alejado de cualquier tipo de método mágico que permita la sobrecarga por las razones descritas en los comentarios y publicaciones SIN EMBARGO , recientemente me encontré con una API de terceros que uso que utiliza un SERVICIO y un SUBSERVICIO, por ejemplo :

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

La parte importante de esto es que esta API tiene todo lo mismo excepto la sub-acción, en este caso doActionOne. La idea es que el desarrollador (yo y otras personas que usen esta clase) podría llamar al subservicio por su nombre en lugar de algo como:

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

Podría hacer en su lugar:

 $myClass->doActionOne($args);

Para codificar no sería más que una gran cantidad de duplicación (este ejemplo esta muy asemeja vagamente el 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();
    }

Pero con el método mágico de __call()puedo acceder a todos los servicios con métodos dinámicos:

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

El beneficio de esta llamada dinámica para la devolución de datos es que si el proveedor agrega otro subservicio, no tengo que agregar otro método a la clase o crear una clase extendida, etc. No estoy seguro de si esto es útil para nadie, pero pensé que podría mostrar un ejemplo donde __set, __get, __call, etc. puede ser una opción para su consideración ya que la función principal es la devolución de datos.


EDITAR:

Casualmente, vi esto unos días después de la publicación, que describe exactamente mi escenario. No es la API a la que me refería, pero la aplicación de los métodos es idéntica:

¿Estoy usando la API correctamente?

Rasclatt
fuente
-2

Actualización: No use esta respuesta ya que este es un código muy tonto que encontré mientras aprendía. Simplemente use getter y setter simples, es mucho mejor.


Por lo general, uso ese nombre de variable como nombre de función, y agrego un parámetro opcional a esa función para que cuando el llamante complete ese parámetro opcional, luego lo establezca en la propiedad y devuelva $ este objeto (encadenamiento) y luego cuando ese parámetro opcional no se especifica por persona que llama, acabo de devolver la propiedad a la persona que llama.

Mi ejemplo:

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
fuente
Ahora queda la pregunta: ¿cómo establecer una propiedad en la cadena vacía? ¿Y cómo detecta que la configuración de una propiedad para la cadena vacía realmente falló y funcionó como un captador? Solo piense en los formularios HTML que envían campos vacíos como cadenas ... Y no: el uso de un valor diferente como NULL como valor predeterminado no resuelve el problema.
Sven