Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 19
  1. #1

    [PHP OOP] Patterns: ObjectValue

    Buona sera,

    vorrei spendere alcune parole sui patterns PHP, cosi ho pensato di stilare una serie di post dove verranno esaminati alcuni dei più utili e famosi patterns finora elaborati.

    Al giorno d'oggi credo che moltissimi programmatori a livello OOP facciano largo uso di patterns che possono facilitare la vita.
    Essendo i design patterns delle ottimali risoluzioni a problemi comuni di programmazione, credo che una analisi dei più comuni possa essere d'aiuto a molti.

    Oggi come primo pattern vediamo ObjectValue
    Quando ci riferiamo ai "value object" parliamo di oggetti non molto complessi la cui egualianza in riferimento ad altri oggetti si basa sui valori assegnati ai suoi campi e non sulla sua identità.

    In parole più semplici:
    Prendiamo il caso di avere 2 utenti con lo stesso nome e nessun campo ID che ci permette di distinguerne l'identità. Questi due oggetti sono "value object" perchè la loro ugualianza si basa sui valori assegnati alle proprietà (il nome).

    - A livello teorico se noi associassimo un identità (ID) ai due utenti improvvisamente ci ritroviamo per le mani due entità ma ne parleremo più avanti nei prossimi post.

    Un'altra caratteristica del "value object" è la sua immutabilità, questo significa semplicemente che una volta che i sui campi sono stati popolati con i valori, questi non si possono più cambiare.

    Dopo questa prefazione teorica iniziamo a mettere mano al codice e vedrete che sarà tutto molto più chiaro.

    L'intento di questo esempio è quello di spiegare come creare "value object" che potrebbero esistere in un ambiente reale.
    Prenderemo quindi in considerazione una ipotetica classe URL
    Codice PHP:
    final class url {

        private 
    $scheme;
        private 
    $host;
        private 
    $path;
        private 
    $querystring;

        public function 
    __construct$url ) {
            if ( !
    filter_var$urlFILTER_VALIDATE_URL, array( FILTER_FLAG_SCHEME_REQUIREDFILTER_FLAG_HOST_REQUIRED ) ) ) {
                throw new 
    Exception"L'url he hai specificato non è valido!" );
            }

            
    $url parse_url$url );
            
    $this->scheme $url['scheme'];
            
    $this->host $url['host'];

            if ( isset( 
    $url['path'] ) ) {
                
    $this->path $url['path'];
            }

            if ( isset( 
    $url['query'] ) ) {
                
    $this->queryString $url['query'];
            }
        }

    Classe molto semplice, abbiamo un url in ingresso e lo scomponiamo popolando le proprietà dell'oggetto. Niente di alieno
    L'aspetto importante da notare qui, oltre alla semplicità del codice, è l'immutabilità del nostro "value object", una volta assegnati i valori non possiamo più modificarli.

    Nel prossimo post vediamo di aggiungere qualche getter alla nostra classe per renderla più carina
    Questa volta, più che un voto.. è favoreggiamento.

  2. #2
    Quote Originariamente inviata da Al_katraz984 Visualizza il messaggio
    Buona sera,
    Nel prossimo post vediamo di aggiungere qualche getter alla nostra classe per renderla più carina
    Anche perchè senza getter, essendo gli attributi privati, il value object sarebbe inutilizzabile.
    "Mai discutere con un idiota. Ti trascina al suo livello e ti batte con l'esperienza." (Oscar Wilde)

  3. #3
    Ecco la seconda parte,

    chi ha già masticato OOP sarà in grado di completare la classe con i getters ma per gli altri posto l'implementazione dei metodi necessari.

    Codice PHP:
        public function getScheme() {
            return 
    $this->scheme;
        }

        public function 
    getHost() {
            return 
    $this->host;
        }

        public function 
    getPath() {
            return 
    $this->path;
        }

        public function 
    getQuerystring() {
            return 
    $this->querystring;
        } 
    Et voilà ecco i nostri getters per la classe niente di complesso mi sembra. In questo modo diamo la possibilità di accedere alle proprietà private della classe anche dall'esterno.

    ed ecco la nostra classe completa:
    Codice PHP:
    final class url {

        private 
    $scheme;
        private 
    $host;
        private 
    $path;
        private 
    $querystring;

        public function 
    __construct$url ) {
            if ( !
    filter_var$urlFILTER_VALIDATE_URL, array( FILTER_FLAG_SCHEME_REQUIREDFILTER_FLAG_HOST_REQUIRED ) ) ) {
                throw new 
    Exception"L'url he hai specificato non è valido!" );
            }

            
    $url parse_url$url );
            
    $this->scheme $url['scheme'];
            
    $this->host $url['host'];

            if ( isset( 
    $url['path'] ) ) {
                
    $this->path $url['path'];
            }

            if ( isset( 
    $url['query'] ) ) {
                
    $this->queryString $url['query'];
            }
        }

        public function 
    getScheme() {
            return 
    $this->scheme;
        }

        public function 
    getHost() {
            return 
    $this->host;
        }

        public function 
    getPath() {
            return 
    $this->path;
        }

        public function 
    getQuerystring() {
            return 
    $this->querystring;
        }

    Molto bene, abbiamo una classe che ci permette di modellare un "value object" niente di complesso mi sembra, nella 2a parte diamo un po' di movimento alla classe ma per ora mi fermo qui.

    Spero sia chiaro e utile a qualcuno per chi ha domande rispondete sotto e cercate di restare in tema.
    Grazie
    Andrea
    Questa volta, più che un voto.. è favoreggiamento.

  4. #4
    Quote Originariamente inviata da satifal Visualizza il messaggio
    Anche perchè senza getter, essendo gli attributi privati, il value object sarebbe inutilizzabile.
    è la teoria che conta
    Questa volta, più che un voto.. è favoreggiamento.

  5. #5
    Utente di HTML.it L'avatar di Grino
    Registrato dal
    Oct 2004
    Messaggi
    739
    Non sono un appassionato di pattern e ne capisco ben poco, ma vorrei porre alcune osservazioni e dare il mio contributo. Hai di fatto creato un oggetto costante ossia essendo le classi delle definizioni di tipi e raltive operazioni possibli, non fai altro che definire uno stato per la classe impedendone la modifica. Ma essendo una costante, non dovrei ottenere sempre lo stesso oggetto, a parità di parametri in ingresso, all'atto della creazione? In altre parole il valore 10 è tale a prescindere dalla variabile a cui è assegnato così come uno stato costate di un oggetto dovrebbe essere tale aprescindere dall'oggetto istanziato ossia l'istanza è sempre la stessa.

    Io avrei svolto il compitino in questo modo:

    Codice PHP:
    <?php

    class OggettoCostante {

        private static 
    $gliOggetti = [];
        private 
    $iDati = [];

        
    /**
         * Crea un nuovo oggetto costante. In $valori vanno specificate coppie
         * [nomeProprietà => valore, ...]. Le proprietà saranno poi accessibili
         * tramite la sintassi $oggetto->nomeProprietà in sola lettaura
         * @param array $valori
         * @return type
         */
        
    public static function creaNuovoOggetto(array $valori) {
            
    $hash hash("sha256"serialize($valori)); //tengo le dita incrociate

            
    if (!isset(self::$gliOggetti[$hash]))
                
    self::$gliOggetti[$hash] = new OggettoCostante($valori);

            return 
    self::$gliOggetti[$hash];
        }

        private function 
    __construct(array $valori) {
            foreach (
    $valori as $nomeProprieta => $valore) {
                if (
    is_object($valore))
                    
    $valore = clone $valore;
                
    $this->iDati[$nomeProprieta] = $valore;
            }
        }

        public function 
    __get($name) {
            if (isset(
    $this->iDati[$name]))
                return 
    $this->iDati[$name];

            throw new 
    Exception("La proprieta non e' definita");
        }

        public function 
    __set($name$value) {
            throw new 
    Exception("Non e' ammessa la modifica dello stato dell'oggetto");
            ;
        }

    }

    final class 
    URL extends OggettoCostante {

        
    /**
         * Crea un nuovo oggetto url costante. Il parametro è un array del tipo:
         * ['url' => 'http://www.google.com']
         * @param array $url
         * @throws Exception
         */
        
    public static function creaNuovoOggetto(array $url) {
             if (!isset(
    $url['url']) or !filter_var($url['url'],  FILTER_VALIDATE_URL, array(FILTER_FLAG_SCHEME_REQUIRED,  FILTER_FLAG_HOST_REQUIRED))) {
                throw new 
    Exception("Parametro non correttamente formattato o url non valido.");
            }

            
    $purl parse_url($url['url']);
            
    $scheme $purl['scheme'];
            
    $host $purl['host'];
            
    $path = (isset($purl['path'])) ? $purl['path'] : 'undefined';
            
    $query = (isset($purl['query'])) ? $purl['query'] : 'undefined';

             return 
    parent::creaNuovoOggetto(array('url' => $url['url'], 'scheme'  => $scheme'host' => $host'path' => $path'query' =>  $query));
        }

    }

    //script di test
    try {
        
    $test URL::creaNuovoOggetto(['url' => 'h*t*t*p://www.test.it/index.php?q=paperino']);
        
    $test1 URL::creaNuovoOggetto(['url' => 'h*t*t*p://www.test.it/index.php?q=paperino']);
        
    $test2 URL::creaNuovoOggetto(['url' => 'h*t*t*p://www.test.com/index.php?q=paperino']);
        
    var_dump($test == $test1);
        
    var_dump($test2 == $test1);
         echo 
    $test->url '<br>' $test->scheme '<br>' .  $test->host '<br>' $test->path '<br>' .  $test->query '<br>';
        
    $test->url 'Pippo';
    } catch (
    Exception $e) {
        echo 
    $e->getMessage();
    }
    ?>
    L'output dello script di test è:

    codice:
    boolean true
    boolean false
    h*t*t*p*://w*w*w*.test.it/index.php?q=paperino
    http
    w*w*w*.test.it
    /index.php
    q=paperino
    Non e' ammessa la modifica dello stato dell'oggetto
    in questo modo hai la possibilità di:
    1) accedere alle prorpietà direttametne tramite il loro nome senza permetterene la modifica
    2) poter verificare che lo stato sia lo stesso per due oggetti OggettoCostante, e per ereditarità URL, semplicemente utlizzando l'operatore di confronto == dato che oggetti con uguale stato utilizzano lo stesso oggetto

    in più OggettoCostante è sufficientemente generico da poter essere utilizzato e riutilizzato in ogni circostanza, direttamente o per specializzazione come nel caso di URL riducendo il codice necessario e semplificandone la stesura.

    Ovviamente il tutto è opinabile sebbene questo sia il mio metodo.

    Nota gli * in più sono per nascondere gli url altrimenti non potevo postare

    Siamo sempre troppo gelosi delle nostre grandi piccole opere! - Grino inedito.
    Lavori e Lavoretti

  6. #6
    @Grino

    Due value object sono uguali non perchè sono la stessa istanza ma perchè il loro valore è lo stesso. Tutto quel casino che praticamente è un singleton mi sembra "fuori pattern".
    IP-PBX management: http://www.easypbx.it

    Old account: 2126 messages
    Oldest account: 3559 messages

  7. #7
    Quote Originariamente inviata da Grino Visualizza il messaggio
    Ovviamente il tutto è opinabile sebbene questo sia il mio metodo.

    Nota gli * in più sono per nascondere gli url altrimenti non potevo postare

    Grazie per il contributo , quando posto la seconda parti chiarisco anche il concetto di immutabilità.

    E' molto più semplice di quello che immagini

    (x i mod, ci saranno circa 3 o 4 parti per questo pattern, le posto qui o faccio 3 topic con i link di riferimento?) Mantengo uniti gli stessi argomenti o meglio se li spezzo?
    Questa volta, più che un voto.. è favoreggiamento.

  8. #8
    Quote Originariamente inviata da Al_katraz984 Visualizza il messaggio
    (x i mod, ci saranno circa 3 o 4 parti per questo pattern, le posto qui o faccio 3 topic con i link di riferimento?) Mantengo uniti gli stessi argomenti o meglio se li spezzo?
    io voto per un topic a pattern, non un topic per parte di pattern
    IP-PBX management: http://www.easypbx.it

    Old account: 2126 messages
    Oldest account: 3559 messages

  9. #9
    Quote Originariamente inviata da Santino83_02 Visualizza il messaggio
    io voto per un topic a pattern, non un topic per parte di pattern
    ho visto che nella modalità avanzata posso mettere anche il titolo del post cosi segnalo le parti... Per me ok tutto su un topic, sentiamo il primo mod che passa cosa dice
    Questa volta, più che un voto.. è favoreggiamento.

  10. #10
    Utente di HTML.it L'avatar di Grino
    Registrato dal
    Oct 2004
    Messaggi
    739
    Quote Originariamente inviata da Santino83_02 Visualizza il messaggio
    @Grino

    Due value object sono uguali non perchè sono la stessa istanza ma perchè il loro valore è lo stesso. Tutto quel casino che praticamente è un singleton mi sembra "fuori pattern".
    @Santino83_02

    Quello che ho cercato di dire, ma non sei stato in grado di capire è, perchè se ho due oggetti con uno stato interno invariabile (immutabile o che non cambia nel tempo) devo istanziare due aree di memoria distinte?

    Ne alloco solo una e se tenti di creare un nuovo oggetto con lo stesso stato di uno già esistente (immutabile essendo un value object) ti restituisco quello già creato, altrimenti te ne creo uno nuovo e lo trattengo internamente per restituirlo qualora chiedessi un'ulteriore oggetto con il medesimo stato.

    In più, supponendo che wikipedia sia affidabile, per il value object troviamo scritto:
    In computer science, a value object is a small object that represents a simple entity whose equality isn't based on identity: i.e. two value objects are equal when they have the same value, not necessarily being the same object

    Il fatto che si dica che due value object "non debbano necessariamente essere lo stesso oggetto" non vuol dire che se mi chiedi un'oggetto con un stato X n volte io non possa restituirti la stessa istanza contenente lo stato X. E se mi chiedi un oggetto m volte con stato Y io non possa restituiti m volte sempre la stessa istanza di un oggetto con stato Y.

    Il fatto che io restituisca a parità di stato sempre la stessa istanza ha come effetto secondario che potrai confrontare indistintamente i due oggetti o tramite il loro stato interno (proprietà per proprietà) o tramite il riferimento all'oggetto che è sempre lo stesso.

    Mi dispiace contraddirti ma non è un singleton considerato che, come da script d'esempio in cui il secondo boolean di test ritorna false (var_dump($test2 == $test1);), cercando di creare oggetti costanti con stato interno diverso ottieni istanze diverse, come dire che 10 non è ugaule a 11. Il singleton crea un'unica istanza dell'oggetto e ritorna sempre quella. La mia classe invece crea n oggetti distinti se distinto è lo stato che cerchi di assegnare in prima istanza.

    I pattern non sono la bibbia ma sono buone prassi. Se i pattern dovessero essere punto di arrivo della programmazione, oggi scriveremmo ancora spaghetti code. Se programmare vuol dire applicare cecamente un pattern, allora è giusto che i programmatori guadagnino una miseria poichè svolgono un banalissimo lavoro meccanico, ma non credo sia così.

    In più ho difficoltà a credere che tu non riesca a leggere e capire il codice che ho scritto, visto le competenze che hai più volte dimostrato, al punto da definirlo un casino.

    Siamo sempre troppo gelosi delle nostre grandi piccole opere! - Grino inedito.
    Lavori e Lavoretti

Tag per questa discussione

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.