IMPORTANT: Per accedir als fitxer de subversion: http://acacha.org/svn (sense password). Poc a poc s'aniran migrant els enllaços. Encara però funciona el subversion de la farga però no se sap fins quan... (usuari: prova i la paraula de pas 123456)

Named Constructors in PHP

Amb PHP només podem tenir un sol constructor i això sovint és un limitació important. Per exemple imagineu un objecte Time:

$time = new Time("11:45");
$time = new Time(11, 45);
$minutesSinceMidnight = 705;
$time = new Time($minutesSinceMidnight);

Les tres opcions poden ser interessants no? (vegeu Carbon) Perpo amb PHP cal fer tot el codi en un sol constructor i el codi serà lleig:

final class Time
{
    private $hours, $minutes;
    public function __construct($timeOrHours, $minutes = null)
    {
        if(is_string($timeOrHours) && is_null($minutes)) {
            list($this->hours, $this->minutes) = explode($timeOrHours, ':', 2);
        } else {
            $this->hours = $timeOrHours;
            $this->minutes = $minutes;
        }
    }
}

I anirà empitjorant quantes més opcions afegim! Un solució és crear constructors amb nom vegeu un exemple

<?php
final class Time
{
    private $hours, $minutes;

    public function __construct($hours, $minutes)
    {
        $this->hours = (int) $hours;
        $this->minutes = (int) $minutes;
    }

    public static function fromString($time)
    {
        list($hours, $minutes) = explode($time, ':', 2);
        return new Time($hours, $minutes);
    }

    public static function fromMinutesSinceMidnight($minutesSinceMidnight)
    {
        $hours = floor($minutesSinceMidnight / 60);
        $minutes = $minutesSinceMidnight % 60;
        return new Time($hours, $minutes);
    }
}

Ara cada mètode compleix amb el Single Responsibility Principle. La interfície pública és clara i comprensible i les implementacions són senzilles i directes.

De fet encara podem anar més enllà i eliminar el constructor i forçar a utilitzar els named constructors:

 <?php
final class Time
{
    private $hours, $minutes;

    // We don't remove the empty constructor because it still needs to be private
    private function __construct(){} 

    public static function fromValues($hours, $minutes)
    {
        $time = new Time;
        $time->hours = $hours;
        $time->minutes = $minutes;
        return $time;
    }
    
    public static function fromString($time)
    {
        list($hours, $minutes) = explode($time, ':', 2);
        return new Time($hours, $minutes);
    }

    public static function fromMinutesSinceMidnight($minutesSinceMidnight)
    {
        $hours = floor($minutesSinceMidnight / 60);
        $minutes = $minutesSinceMidnight % 60;
        return new Time($hours, $minutes);
    }
}

Alternatives

Factory + Fluent Style (Method Chaining)

Un exemple ([1]):

<?php

class Student
{

    protected $firstName;
    protected $lastName;
    // etc.

    /**
     * Constructor
     */
    public function __construct() {
        // allocate your stuff
    }

    /**
     * Static constructor / factory
     */
    public static function create() {
        $instance = new self();
        return $instance;
    }

    /**
     * FirstName setter - fluent style
     */
    public function setFirstName( $firstName) {
        $this->firstName = $firstName;
        return $this;
    }

    /**
     * LastName setter - fluent style
     */
    public function setLastName( $lastName) {
        $this->lastName = $lastName;
        return $this;
    }

}

// create instance
$student= Student::create()->setFirstName("John")->setLastName("Doe");

// see result
var_dump($student);

Factory pattern

Vegeu Factory pattern s'assembla molt

Vegeu també

Enllaços externs