Domanda

(Questa domanda utilizza PHP come contesto ma non è limitata solo a PHP.per esempio.È rilevante anche qualsiasi linguaggio con hash integrato)

Diamo un'occhiata a questo esempio (PHP):

function makeAFredUsingAssoc()
{
    return array(
        'id'=>1337,
        'height'=>137,
        'name'=>"Green Fred");
}

Contro:

class Fred
{
    public $id;
    public $height;
    public $name;

    public function __construct($id, $height, $name)
    {
        $this->id = $id;
        $this->height = $height;
        $this->name = $name;
    }
}

function makeAFredUsingValueObject()
{
    return new Fred(1337, 137, "Green Fred");
}

Il metodo n. 1 è ovviamente più conciso, tuttavia può facilmente portare a errori come

$myFred = makeAFredUsingAssoc();
return $myFred['naem']; // notice teh typo here

Naturalmente, si potrebbe obiettare questo $myFred->naem porterà ugualmente all’errore, il che è vero.Tuttavia avere una lezione formale mi sembra semplicemente più rigido, ma non posso davvero giustificarlo.

Quali sarebbero i pro/contro nell’utilizzo di ciascun approccio e quando le persone dovrebbero utilizzare quale approccio?

È stato utile?

Soluzione

Sotto la superficie, i due approcci sono equivalenti. Tuttavia, si ottiene la maggior parte dei benefici OO standard, quando si utilizza una classe:. Incapsulamento, ereditarietà, etc

Inoltre, guardare i seguenti esempi:

$arr['naem'] = 'John';

è perfettamente valido e potrebbe essere un bug difficile da trovare.

D'altra parte,

$class->setNaem('John');

non funzionerà mai.

Altri suggerimenti

Una semplice classe come questa:

class PersonalData {
    protected $firstname;
    protected $lastname;

    // Getters/setters here
}

ha pochi vantaggi rispetto ad un array.

  1. Non v'è alcuna possibilità di fare alcuni errori di battitura. $data['firtsname'] = 'Chris'; funzionerà mentre $data->setFirtsname('Chris'); getterà en errore.
  2. Tipo hinting:. Array PHP possono contenere tutto (incluso niente) mentre la classe ben definita contiene solo i dati specificati

    public function doSth(array $personalData) {
        $this->doSthElse($personalData['firstname']); // What if "firstname" index doesn't exist?
    }
    
    
    public function doSth(PersonalData $personalData) {
        // I am guaranteed that following method exists. 
        // In worst case it will return NULL or some default value
        $this->doSthElse($personalData->getFirstname());
    }
    
  3. Si può aggiungere un po 'di codice in più prima di Set / Get operazioni, come la convalida o la registrazione:

    public function setFirstname($firstname) {
        if (/* doesn't match "firstname" regular expression */) {
            throw new InvalidArgumentException('blah blah blah');
        }
    
    
    
    if (/* in debbug mode */) {
        log('Firstname set to: ' . $firstname);
    }
    
    
    $this->firstname = $firstname;
    
    }
  4. Si può utilizzare tutti i vantaggi della programmazione orientata agli oggetti, come ereditarietà, polimorfismo, il tipo di hinting, incapsulamento e così via ...
  5. Come accennato prima tutti i nostri "struct" può ereditare da una classe base che fornisce l'implementazione per le interfacce Countable, Serializable o Iterator, così i nostri le strutture potrebbero utilizzare foreach loop etc.
  6. supporto IDE.

L'unico svantaggio sembra essere la velocità. Creazione di un array e operante su esso è più veloce. Tuttavia tutti sappiamo che in molti casi il tempo di CPU è molto più economico tempo programmatore. ;)

Dopo averci pensato per un po ', ecco la mia risposta.

La cosa principale di preferendo oggetti di valore sopra array è chiarezza .

Consideriamo questa funzione:

// Yes, you can specify parameter types in PHP
function MagicFunction(Fred $fred)
{
    // ...
}

vs

function MagicFunction(array $fred)
{
}

L'intento è chiara. La funzione di autore può far valere la sua esigenza.

Ancora più importante, come l'utente, posso facilmente cercare ciò che costituisce una valida Fred . Ho solo bisogno di aprire Fred.php e scoprire i suoi interni.

C'è un contratto tra il chiamante e il chiamato. Utilizzando oggetti di valore, questo contratto può essere scritto come codice sintassi-controllato:

class Fred
{
    public $name;
    // ...
}

Se ho usato un array, posso solo sperare il mio utente avrebbe letto i commenti o la documentazione:

// IMPORTANT! You need to specify 'name' and 'age'
function MagicFunction(array $fred)
{
}

A seconda del caso d'uso che potrei usare o. Il vantaggio della classe è che posso usarlo come un tipo e utilizzare i parametri di tipo sui metodi o qualsiasi metodo di introspezione. Se voglio solo passare intorno ad alcuni set di dati a caso da una query o qualcosa del genere, avrei probabilmente utilizzare la matrice. Quindi credo che fintanto che Fred ha un significato speciale nel mio modello, userei una classe.

Su un sidenote:
ValueObjects si suppone essere immutabili. Almeno se si sta riferendo alla definizione di Eric Evan nel Domain Driven Design. In PoEA di Fowler, ValueObjects non necessariamente devono essere immutabili (anche se è suggerito), ma non dovrebbero avere identità, che è chiaramente il caso con Fred .

Mi permetta di pongo questa domanda a voi:

Cosa c'è di così diverso di fare un errore di battitura come $myFred['naem'] e facendo un errore di battitura come $myFred->naem? Lo stesso problema esiste ancora in entrambi i casi ed entrambi errore.

Mi piace usare BACIO (mantenerlo semplice, stupido) quando programmo.

  • Se si sta semplicemente restituendo un sottoinsieme di una query da un metodo, semplicemente restituire un array.
  • Se si memorizzano i dati come una variabile pubblico / privato / static / protetto in una delle classi, sarebbe meglio per conservare come uno stdClass.
  • Se avete intenzione di passare entro la fine ad un altro metodo di classe, si potrebbe preferire la tipizzazione della classe Fred, vale a dire public function acceptsClass(Fred $fredObj)

Si potrebbe avere altrettanto facilmente creato una classe normale in contrapposizione ad un array se deve essere usato come valore di ritorno. In questo caso si potrebbe interessare di meno la tipizzazione.

$class = new stdClass();
$class->param = 'value';
$class->param2 = 'value2';
return $class;

Un professionista per l'hash: E 'in grado di gestire le combinazioni nome-valore che sono sconosciuti in fase di progettazione

.

Quando il valore di ritorno rappresenta un'entità nell'applicazione, è necessario utilizzare un oggetto, in quanto questo è lo scopo della programmazione orientata agli oggetti. Se si desidera solo per restituire un gruppo di valori estranei allora non è così netta. Se si tratta di una parte di un'API pubblica, però, poi una classe dichiarata è ancora il modo migliore per andare.

Onestamente, mi piacciono entrambi.

  • array di hash sono il modo più veloce di rendere gli oggetti, e il tempo è denaro!
  • Ma, JSON non piace array hash (che sembra un po 'come OOP OCD).
  • Forse per i progetti con più persone, una classe ben definita sarebbe meglio.
  • array di hash potrebbe richiedere più tempo di CPU e della memoria (un oggetto ha una quantità predefinita), anche se la sua difficile essere sicuri per ogni scenario.

Ma ciò che veramente schifo sta pensando a quale usare troppo. Come ho detto, JSON non piace hash. Oops, ho utilizzato un array. Ho avuto modo di cambiare qualche migliaio di righe di codice ora.

Non mi piace, ma sembra che le classi sono il modo più sicuro di andare.

Il vantaggio di una corretta valore dell'oggetto è che non c'è modo di fare in realtà un uno non valido e non c'è modo di cambiare quella che esiste (integrità e "immutabilità"). Con solo getter e parametri di tipo hinting, non c'è modo di rovinare tutto nel codice compilabile, che ovviamente è possibile fare facilmente con gli array malleabili.

In alternativa si potrebbe validare in un costruttore pubblico e un'eccezione, ma questo fornisce un metodo factory più delicato.

class Color
{
    public static function create($name, $rgb) {
        // validate both
        if ($bothValid) {
            return new self($name, $rgb);
        } else {
            return false;
        }
    }
    public function getName() { return $this->_name; }
    public function getRgb() { return $this->_rgb; }

    protected function __construct($name, $rgb)
    {
        $this->_name = $name;
        $this->_rgb = $rgb;
    }
    protected $_name;
    protected $_rgb;
}

Lavoro con OOP Languages ​​da oltre 10 anni.Se capisci il modo in cui funzionano gli oggetti, lo adorerai.Ereditarietà, polimorfismo, incapsulamento e sovraccarico sono i principali vantaggi dell'OOP.D'altra parte quando parliamo di PHP dobbiamo considerare che PHP non è un linguaggio orientato agli oggetti completo di funzionalità.Ad esempio, non possiamo utilizzare l'overload del metodo o l'overload del costruttore (diretto).

Gli array associativi in ​​PHP sono una funzionalità MOLTO interessante, ma penso che danneggi le applicazioni aziendali php.Quando scrivi codice vuoi ottenere un'applicazione pulita e manutenibile.

Un'altra cosa che perdi con gli array associativi è che non puoi usare Intellisense.

Quindi penso che se vuoi scrivere un codice più pulito e più gestibile devi utilizzare le funzionalità OOP quando vengono fornite.

Io preferisco avere proprietà hard-coded, come nel secondo esempio. Mi sento come definisce più chiaramente la struttura di classe atteso (e tutte le possibili immobili in classe). A differenza del primo esempio, che si riduce a solo ricordando sempre di utilizzare gli stessi nomi chiave. Con la seconda si può sempre tornare indietro e guardare la classe per avere un'idea delle proprietà solo guardando la parte superiore del file.

Ti meglio sapere che stai facendo qualcosa di sbagliato con il secondo -. Se si tenta di echo $this->doesntExist si otterrà un errore che, se si tenta di echo array['doesntExist'] che non lo farai

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top