style standard recommendation psr2 psr name code php coding-style

php - standard - Mejores prácticas para constructores estáticos



psr 3 php (8)

Además de la respuesta de Jon : Para permitir argumentos de constructor, use lo siguiente:

function create($type) { $args = func_get_args(); $reflect = new ReflectionClass(array_shift($args)); return $reflect->newInstanceArgs($args); } create(''Foo'', ''some'', ''args'')->bar();

Documentación: ReflectionClass -> newInstanceArgs

Quiero crear una instancia de una clase y llamar a un método en esa instancia, en una sola línea de código.

PHP no permitirá llamar a un método en un constructor regular:

new Foo()->set_sth(); // Outputs an error.

Entonces estoy usando, si puedo llamarlo así, un constructor estático:

Foo::construct()->set_sth();

Aquí está mi pregunta:

¿Es una buena práctica usar constructores estáticos como ese y, en caso afirmativo, cómo recomendaría que se nombren los métodos para estos constructores estáticos?

He estado dudando sobre las siguientes opciones:

Foo::construct(); Foo::create(); Foo::factory() Foo::Foo(); constructor::Foo();


El nombramiento de cualquier método debe ser con la intención de revelar nombres . No puedo decir lo que hace ''Foo :: factory''. Trate de construir a un lenguaje de nivel superior:

User::with100StartingPoints();

Esto sería lo mismo que:

$user = new User(); $user->setPointsTo(100);

También puede probar fácilmente si User :: with100StartingPoints () es igual a esto.


Estos se denominan métodos de creación , y normalmente los createXXX() como createById() o createEmptyCatalog() . No solo proporcionan una buena forma de revelar las diferentes intenciones de los constructores de un objeto, sino que también permiten el encadenamiento inmediato de métodos en una interfaz fluida.

echo Html_Img::createStatic(''/images/missing-image.jpg'') ->setSize(60, 90) ->setTitle(''No image for this article'') ->setClass(''article-thumbnail'');


Los constructores estáticos (o "constructores nombrados") solo son beneficiosos para demostrar una intención, como dice @koen.

Sin embargo, desde la versión 5.4, apareció algo llamado "desreferenciación", lo que le permite crear una instancia de clase en línea directamente con una llamada de método.

(new MyClass($arg1))->doSomething(); // works with newer versions of php

Por lo tanto, los constructores estáticos solo son útiles si tiene varias formas de crear una instancia de sus objetos. Si solo tiene uno (siempre el mismo tipo de argumentos y número de argumentos), no hay necesidad de constructores estáticos.

Pero si tiene múltiples formas de crear instancias, entonces los constructores estáticos son muy útiles, ya que evita contaminar su constructor principal con una inútil verificación de argumentos, lo que debilita las restricciones de idiomas.

Ejemplo:

<?php class Duration { private $start; private $end; // or public depending if you still want to allow direct instantiation private function __construct($startTimeStamp = null, $endTimestamp = null) { $this->start = $startTimestamp; $this->end = $endTimestamp; } public static function fromDateTime(/DateTime $start, /DateTime $end) { return new self($start->format(''U''), $end->format(''U'')); } public static function oneDayStartingToday() { $day = new self; $day->start = time(); $day->end = (new /DateTimeImmutable)->modify(''+1 day'')->format(''U''); return $day; } }

¡Como puede ver en oneDayStartingToday , el método estático puede acceder a los campos privados de la instancia! ¿Loco no es así? :)

Para una mejor explicación, vea http://verraes.net/2014/06/named-constructors-in-php/


Probablemente no sea una buena práctica , pero podría usar el hecho de que las funciones y las clases tienen dos espacios de nombres diferentes: puede tener una función que tenga el mismo nombre que una clase.

Esto permite escribir este tipo de código, por ejemplo:

function MyClass() { return new MyClass(); } class MyClass { public function __construct() { $this->a = "plop"; } public function test() { echo $this->a; } protected $a; }

Tenga en cuenta que he definido una función llamada MyClass y una clase con el mismo nombre.


Entonces, puedes escribir esto:

MyClass()->test();

Lo que funcionará a la perfección, y no obtendrá ningún error: aquí obtendrá el siguiente resultado:

plop


Propel utiliza un método estático "crear". Yo iría con eso. Este método hace que el código sea más fácil de probar en lugar de usar métodos estáticos para realizar la lógica de negocios.

<?php class MyClass { public static function create() { return new MyClass(); } public function myMethod() { } }

Además, también puedes pasar parámetros al constructor. Por ejemplo:

<?php class MyClass { public function __construct($param1, $param2) { //initialization using params } public static function create($param1, $param2) { return new MyClass($param1, $param2); // return new self($param1, $param2); alternative ;) } public function myMethod() { } }

En cualquier caso, podrá invocar myMethod justo después del método de creación.

<?php MyClass::create()->myMethod(); // or MyClass::create($param1, $param2)->myMethod();


Si no necesita una referencia al Foo recién construido, ¿por qué no hace simplemente que set_sth una función static (y haga que cree un nuevo Foo internamente si es necesario)?

Si necesita obtener la referencia, ¿cómo lo haría? return $this en set_sth ? Pero entonces set_sth puede convertirse en una función de fábrica de todos modos.

La única situación en la que puedo pensar es si desea llamar a métodos chainable (como en una interfaz fluida) en una instancia recién construida, todo en una expresión. ¿Es eso lo que estás tratando de hacer?

De todos modos, puede utilizar una función de fábrica de propósito general para todos los tipos de objetos, por ejemplo,

function create_new($type) { return new $type; } create_new(''Foo'')->set_sth();


Un poco tarde para la fiesta pero creo que esto podría ayudar.

class MyClass { function __construct() { // constructor initializations here } public static myMethod($set = null) { // if myclass is not instantiated if (is_null($set)) { // return new instance $d = new MyClass(); return $d->Up(''s''); } else { // myclass is instantiated // my method code goes here } } }

esto puede ser utilizado como

$result = MyClass::myMethod();

los parámetros opcionales se pueden pasar a través de __constructor o myMethod.
Este es mi primer post y espero tener los trucos correctos.