Pagina 2 di 2 primaprima 1 2
Visualizzazione dei risultati da 11 a 19 su 19

Hybrid View

  1. #1
    Quote Originariamente inviata da Grino Visualizza il messaggio
    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.


    se pazienti, con la seconda parte ti mostro che tutto il codice che tu hai scritto è superfluo.
    Questa volta, più che un voto.. è favoreggiamento.

  2. #2
    Quote Originariamente inviata da Grino Visualizza il messaggio
    @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.


    Si bel pippone di spiegazione, ma il discorso è che non è che perchè voglio un oggetto "immutabile" allora devo usare quella sottospecie di singleton e istanziare ogni volta ogni oggetto con una factory... di Value Object "con gli stessi valori" ne puoi avere seimila, non stà nel pattern impedire che due value object abbiano gli stessi valori, dice solo che il value object deve essere immutabile e che due value object sono uguali se uguali i valori. Il discorso se istanziare o meno N volte un value object dipende da 1) che cosa rappresenta questo value object e 2) da quanti effettivamente ne stai istanziando e 3) ma quante volte vorrai utilizzarlo un value object? in un app web poi... quante ne istanzierai? 1? 2? 3?

    Cmq il mio intervento era semplicemente per dire che la tua implementazione risolve delle specifiche ben precise (non ripetere due volte lo stesso value object) e impone che lo stesso due oggetti che devono usare una istanza del value object puntano entrambi alla stessa istanza, cosa nello specifico inutile e che potrebbe anche risultare controproducente in alcuni casi. Tutto quà... lungi da me l'idea di darti del cretino (cosa che per altro tu hai fatto tranquillamente), dicevo solo che l'implementazione (alias: tutto quel casino... alias alias: tutto quel popò di roba ... alias alias alias: tutte quelle righe di codice) andava secondo me fuori dagli scopi del pattern e che era del tutto opinabile (cosa per altro detta anche da te medesimo). punto.
    IP-PBX management: http://www.easypbx.it

    Old account: 2126 messages
    Oldest account: 3559 messages

  3. #3
    Utente di HTML.it L'avatar di Grino
    Registrato dal
    Oct 2004
    Messaggi
    739
    Non ti darei mai del cretino, a volte però sei un po' frettoloso nel sentenziare.

    Tu scrivi:
    il value object deve essere immutabile e che due value object sono uguali se uguali i valori
    .

    Esattamente quello che fa la mia classe, cercando di non allocare memoria in più. Oviamente con un piccolo overhead d'esecuzione, ma si sa, più sei veloce in esecuzione e più memoria usi, meno memoria usi e meno sei veloce in esecuzione. Quanti ne alloco in un'applicazione web? Non lo so, la sorte sorride a chi si prepara. Infine non mi sembra di aver scritto così tanto codice.

    Codice PHP:
    <?php
    class OggettoCostante {

        private static 
    $gliOggetti = [];
        private 
    $iDati = [];
        
        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");
            ;
        }

    }
    ?>
    Il resto è lo script di test e l'adattamento della classe d'esempio specifica di Al_katraz, ma la classe può essere utilizzata così com'è.

    Se poi non ti piace il fatto che restituisca la stessa istanza a parità di stato, posso strappare via quella parte e rendere pubblico il costruttore. Così ci saranno i soli 3 metodi __construct __get e __set.

    Codice PHP:
    <?php
    class OggettoCostante {
        
        private 
    $iDati = [];       

        public 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");
            ;
        }

    }
    ?>
    Ti piace di più?

    Santino, ti voglio bene (detto sinceramente)! E non ti prendo in giro quando dico che so che ne sai a pacchi.

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

  4. #4

    Patterns: ObjectValue 2a parte

    In questa seconda parte andiamo ad aggiungere un metodo alla classe url che servirà ad "appendere" dei parametri alla querystring. A causa della natura immutabile della classe url, il metodo ritornerà una nuova classe url con i parametri aggiunti alla querystring, dimostrando di fatto l'immutabilità.


    Alcuni classici esempi di "value object" che si usano spesso nelle applicazioni sono: date, numeri di telefono, indirizzi email ect ect.. La struttura degli oggetti, ovviamente, può cambiare in base al contesto di utilizzo e possiamo avere anche altri tipi di "value object" oltre a quelli menzionati, questo dipende sempre dalle necessità del progetto.
    Ad esempio:
    un indirizzo email è composto da parti che dovranno essere attinenti alle specifiche RFC 5321 e RFC 5322

    Purtroppo a differenza di altri programmi tipo C# e Java, PHP non supporta nativamente i "value object" immutabili ma adesso vediamo quanto sia semplice applicare il pattern.

    Siamo partiti con una classe chiusa alla quale abbiamo aggiunto i metodi getter per accedere alle proprietà. Ora per mantenere l'immutabilità della classe (che ci proibisce di modificare il nostro oggetto una volta popolato) realizziamo il metodo addQuerysting()

    Codice PHP:
    public function addQuerystring( array $params ) {
        if ( empty( 
    $params ) ) {
            throw new 
    Exception'I parametri non sono validi' );
        }

        
    $querystring '';
        foreach ( 
    $params AS $key=>$value ) {
            
    $querystring .= '&' $key '=' urlencode$value );
        }

        
    $querystring = ( $this->querystring === NULL 
                        ? 
    trim$querystring'&' 
                        : 
    $this->querystring $querystring;

        
    $url $this->scheme '://' $this->host $this->path '?' $querystring;

        return new 
    url$url );

    Niente di fantascientifico il nostro metodo sfrutta un array associativo con i nuovi parametri da aggiungere alla querystring. L'aspetto importante da notare è che, invece di modificare la querystring esistente, ne creiamo una nuova e la usiamo per creare un nuovo oggetto url (una specie di factory ma ne parleremo più avanti).

    In questo modo abbiamo dimostrato la natura immutabile del nostro "value object" visto che ogni tentativo di modificare i valori assegnati da come risultato un nuovo "value object" dello stesso tipo, preservandone l'immutabilità.
    Questa volta, più che un voto.. è favoreggiamento.

  5. #5

    Patterns: ObjectValue 2a parte

    Molto bene ora abbiamo completato la classe, ora possiamo fare i test:

    url.class.php
    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;
        }

        public function 
    addQuerystring( array $params ) {
            if ( empty( 
    $params ) ) {
                throw new 
    Exception'I parametri non sono validi' );
            }

            
    $querystring '';
            foreach ( 
    $params AS $key=>$value ) {
                
    $querystring .= '&' $key '=' urlencode$value );
            }

            
    $querystring = ( $this->querystring === NULL 
                            ? 
    trim$querystring'&' 
                            : 
    $this->querystring $querystring;

            
    $url $this->scheme '://' $this->host $this->path '?' $querystring;

            return new 
    url$url );
        }

    vediamo un piccolo esempio che dimostra la natura immutabile del "value object"

    Codice PHP:
    require_once( 'url.class.php' );

    $url = new url'http://www.html.it' );

    //aggiungiamo alcuni parametri
    $nuovoUrl $url->addQuerystring( array( 'uid'=>1'name'=>'Paolo' ) );

    if ( 
    $url == $nuovoUrl ) {
        echo 
    'I due "value URL object" sono uguali';
        } else {
        echo 
    'I due "value URL object" NON sono uguali';
    }

    //output: I due "value URL object" NON sono uguali 
    Bene per oggi ho finito, nella prossima parte proviamo a sfruttare i "value object" in altri modi più complessi.

    Spero sia tutto chiaro, ora via con i commenti.
    Ringrazio tutti quelli che stanno contribuendo al topic
    Andrea
    Questa volta, più che un voto.. è favoreggiamento.

  6. #6
    Utente di HTML.it L'avatar di Grino
    Registrato dal
    Oct 2004
    Messaggi
    739
    Se posso, queste sono le mie due versioni alternative di cui una alloca sempre spazio e l'altra cerca di risparmiarlo permettendo l'accesso alle proprietà tramite operatore ->. La classe URL costa di due soli metodi e non ha bisogno di metodi d'accesso. L'accesso in scrittura è ovviamente negato.

    Versione spendacciona:
    Codice PHP:
    <?php
    class OggettoCostante {
        private 
    $iDati = [];

        public 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 {

        public function 
    __construct(array $url) {
            if (!isset(
    $url['url']) or !filter_var($url['url'], FILTER_VALIDATE_URL, array(FILTER_FLAG_SCHEME_REQUIREDFILTER_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'] : '';
            
    $query = (isset($purl['query'])) ? $purl['query'] : '/';

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

        public function 
    addQuery(array $params) {
            if (empty(
    $params))
                throw new 
    Exception('I parametri non sono validi');

            
    $querystring '';
            foreach (
    $params as $key => $value)
                
    $querystring .= '&' $key '=' urlencode($value);

            
    $querystring = (empty($this->query)) ? trim($querystring'&') : $this->query $querystring;

            
    $url $this->scheme '://' $this->host $this->path '?' $querystring;

            return new 
    URL(['url' => $url]);
        }

    }

    $url = new URL(['url' => 'h*t*t*p://www.html.it']);

    //aggiungiamo alcuni parametri
    $nuovoUrl $url->addQuery(array('uid' => 1'name' => 'Paolo'));

    if (
    $url == $nuovoUrl
        echo 
    'I due "value URL object" sono uguali';
     else 
        echo 
    'I due "value URL object" NON sono uguali';

    //output: I due "value URL object" NON sono uguali  
    ?>
    Versione che non istanzia nuovi oggetti a fronte del ripresetnarsi di stati già utilizzati:

    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
            
    $class get_called_class();
            if (!isset(
    self::$gliOggetti[$class][$hash]))
                
    self::$gliOggetti[$class][$hash] = static::istanziaOggetto($valori);
            return 
    self::$gliOggetti[$class][$hash];
        }
        
        protected static function 
    istanziaOggetto(array $valori){
            return new 
    OggettoCostante($valori);
        }

        protected 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'] : '/';
            
    $query = (isset($purl['query'])) ? $purl['query'] : '';
            
            return 
    parent::creaNuovoOggetto(array('url' => $url['url'], 'scheme'  => $scheme'host' => $host'path' => $path'query' =>  $query));
        }
        
        protected static function 
    istanziaOggetto(array $valori) {
            return new 
    URL($valori);
        }

        public function 
    addQuery( array $params ) {
            if ( empty( 
    $params ) )
                throw new 
    Exception'I parametri non sono validi' );        

            
    $querystring '';
            foreach ( 
    $params as $key=>$value 
                
    $querystring .= '&' $key '=' urlencode$value );        

            
    $querystring = (empty($this->query))? trim($querystring'&'):$this->query $querystring;

            
    $url $this->scheme '://' $this->host $this->path '?' $querystring;

            return 
    self::creaNuovoOggetto(['url' => $url]);
        }        
    }

    $url URL::creaNuovoOggetto( ['url' => 'h*t*t*p://www.html.it']);

    //aggiungiamo alcuni parametri
    $nuovoUrl $url->addQuery( array( 'uid'=>1'name'=>'Paolo' ) );

    if ( 
    $url == $nuovoUrl ) {
        echo 
    'I due "value URL object" sono uguali';
        } else {
        echo 
    'I due "value URL object" NON sono uguali';
    }

    //output: I due "value URL object" NON sono uguali  
    ?>
    Inutile dire che l'output prodotto è quello atteso. Non capisco perchè non posso postre indirizzi web nel codice e mi tocca aggiungere gli *

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

  7. #7
    Quote Originariamente inviata da Grino Visualizza il messaggio
    Se posso, queste sono le mie due versioni alternative di cui una alloca sempre spazio e l'altra cerca di risparmiarlo permettendo l'accesso alle proprietà tramite operatore ->.

    ..

    Inutile dire che l'output prodotto è quello atteso. Non capisco perchè non posso postre indirizzi web nel codice e mi tocca aggiungere gli *

    Ok mi sono riletto il codice e ti posto le mie impressioni

    Primo su tutte tendo sempre ad evitare pattern singleton e metodi statici.. Li vedo troppo inconsistenti in un approccio OOP, mi sanno troppo da vecchio "global" che non si capisce mai che attinenza hanno le classi..

    A livello di codice ovviamente il tuo approccio è comunque valido anche se lo vedo un po' troppo articolato.. Un "value object" è un semplice contenitore di informazioni e le informazioni contenute sono diverse da oggetto a oggetto. Vedo molto più semplice definire singolarmente i vari oggetti.

    Vedo anche che ti preoccupi dei tempi di esecuzione, con le nuove versioni di php ci sono le Closures che aprono nuovi mondi sui tempi di caricamento ed esecuzione del codice ma è un argomento che esula dal contesto che stiamo analizzando e credo troppo complesso per ora. Ne parlerò un po' più avanti

    Preparati che nella prossima parte ti complico la vita, vediamo come te la cavi
    grazie intanto

    Ultima modifica di Al_katraz984; 22-12-2013 a 01:35
    Questa volta, più che un voto.. è favoreggiamento.

  8. #8

    Patterns: ObjectValue 3a parte

    Eccoci di nuovo,

    in questa terza parte vi porto un altro esempio di ValueObject, cercheremo di costruire una classe immutabile per creare widget HTML. Qualcosa di più pratico e utile

    Spero di essere stato chiaro fino ad ora e semplice..

    Ok, partiamo
    lo scopo è quello di realizzare un sistema per la creazione di "div" html, iniziamo subito a definire un contratto comune a tutti i widget usando un'interfaccia

    interface.php
    Codice PHP:
    interface htmlWidgetInterface {
        public function 
    render();

    in questo modo tutti gli oggetti che implementano l'interfaccia htmlWidgetInterface dovranno fornire un'implementazione del metodo render().

    Il prossimo passo sarà quello di scrivere una classe in grado di creare i nostri "div"

    div.class.php
    Codice PHP:
    final class div implements htmlWidgetInterface {

        private 
    $content;

        public function 
    __construct$content ) {
            if ( !
    is_string$content ) || empty( $content ) ) {
                throw new 
    Exception'Il contenuto non è valido' );
            }

            
    $this->content $content;
        }

        public function 
    getContent() {
            return 
    $this->content;
        }

        public function 
    nestdiv $div ) {
            
    $content $this->render() . $div->render();
            return new 
    div$content );
        }

        
    // implementazione dell'interfaccia
        
    public function render() {
            return 
    '<div>' $this->content '</div>';
        }

    La classe è molto semplice e facile da capire, passiamo il contenuto al nostro costruttore e con il metodo render() visualizziamo a video il div mantenendo l'immutabilià dell'oggetto.

    Soffermiamoci sul metodo nest().
    Questo metodo ci permette (grazie al type-hinting) di avere la sicurezza che vengano passati solamente oggetti del tipo "div" garantendoci la presenza del metodo render() in quanto sappiamo che la classe div deve avere da contratto un metodo render.

    Proviamo a dimostrare la natura immutabile della nostra classe:
    Codice PHP:
    require_once( 'interface.php' );
    require_once( 
    'div.class.php' );

    $div1 = new div'Contenuto del primo div.' );
    $div2 = new div'Contenuto del secondo div.' );

    $div3 $div1->nest$div2 );
    echo 
    $div3->render();

    //output: 
    // <div><div>Contenuto del primo div.</div><div>Contenuto del secondo div.</div></div> 
    That's it! spero sia chiaro e semplice.
    Per chi si vuole esercitare potete codificare i widget mancanti, ci sono cosi tanti tags html....

    Credo che per quanto riguarda i value object ci siano sufficenti esempi per comprenderne la logica e i concetti. Se qualcuno vuole dire la sua e portare qualche altro esempio ben venga, se ci sono domande fatele, io intanto preparo il prossimo pattern

    Questa volta, più che un voto.. è favoreggiamento.

  9. #9
    Utente di HTML.it L'avatar di Grino
    Registrato dal
    Oct 2004
    Messaggi
    739
    Le feste son feste e quindi con ritardo apporto il mio contributo basato sulla solita precedente teoria che hai ritenuto valida anche se troppo articola e non di tuo gradimento.

    Mi cheidevo per l'esempio specifico che hai presentato perchè inventare una funzione render(), considerato che stai trasformato l'oggetto nella sua rappresentazione stringa tipica per una echo. Quindi perchè non utilizzare __toString(). In più il div è solo uno dei possibili componenti HTML. Non sarebbe meglio se l'objectValue fosse inteso come di tipo htmlWidgetInterface. In questo modo la nest non deve accettare per forza una classe div come argomento, ma può lavorare su una platea di classi (tutte quelle che implementano l'interfaccia). In tal senso il metodo nest rientra nell'interfaccia htmlWidgetInterface. Certo può sembrare di muoversi al di fuori dal pattern, d'altra parte un oggetto che istanzia il tuo div è sia di tipo div che di tipo htmlWidgetInterface, quindi la ritengo cosa ammissibile.

    Codice che istanzia sempre oggetti costanti diversi.

    La classe cOggettoCostante che permette di creare degli oggetti immutabili generici:

    Codice PHP:
    class cOggettoCostante {

        private 
    $iDati = [];

        public 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");
        }


    Come giustamente dici, stabiliamo l'interfaccia di un componente html. Ho cambiato la tua nest in unisci perchè non mi sembra un vero annidamento. In pratica è creato un nuovo oggetto dello stesso tipo dell'oggetto che invoca il metodo e il cui contenuto è la concatenazione dell'oggetto chiamante e dell'oggetto passato come argomento (comunque sempre un oggetto iComponenteHTML). La funzione unisci lavora in modo stretto su oggetti di tipo iComponenteHTML divendo più formale e restituisce un iComponenteHTML. Sarà così possbile ampliare la platea delle classi trattate come oggetti immutabili a tutte quelle classi del mondo HTML che si vorrà definire:

    Codice PHP:
    interface iComponenteHTML {
        public function 
    __toString();
        public function 
    unisci(\iComponenteHTML $contenuto);

    Adesso le classi che gestiscono la produzione HTML. Il div lo ritengo un elemento complesso per poter essere definito in modo diretto. C'è da tenere conto che nella pagina le stringhe di testo vanno codificate con le relative entità HTML senza interferire con i tag di apretura e chiusura degli altri elementi. Così come vanno codificate le stringhe che sono attributo dei tag. Ho quindi strutturato un abbozzo di famiglia di classi, potenzialmente espandibile con altri tag e proprietà per gli elementi class, id, ecc, così organizzata così:

    codice:
    cOggettoCostante
        |
        |-aContenutoBody implementa iComponenteHTML
              |
              |-cStringaHTML
              |
              |-cTag
                    |
                    |-cDiv
    Codice PHP:
    abstract class aContenutoBody extends cOggettoCostante implements iComponenteHTML {

        const 
    contenuto 'contenuto';

        public function 
    __toString() {
            return 
    $this->contenuto;
        }

        abstract public function 
    unisci(\iComponenteHTML $contenuto);

        protected static function 
    verificaContenutoAccettabile($contenuto) {
            return 
    is_string($contenuto) or is_a($contenuto'iComponenteHTML');
        }

    }

    class 
    cStringaHTML extends aContenutoBody {

        public function 
    __construct(array $valori) {
            if (isset(
    $valori[self::contenuto]) and is_string($valori[self::contenuto]))
                
    parent::__construct([self::contenuto => htmlspecialchars($valori[self::contenuto])]);
            else
                throw new 
    Exception("Una stringa HTML deve essere una stringa di testo o contenuto non definito");
        }

        public function 
    unisci(\iComponenteHTML $contenuto) {
            return new 
    cStringa([self::contenuto => $this $contenuto]);
        }

    }

    class 
    cTag extends aContenutoBody {

        const 
    tag 'tag';

        public function 
    __construct(array $valori) {
            if (isset(
    $valori[self::contenuto]) and isset($valori[self::tag]) and self::verificaContenutoAccettabile($valori[self::contenuto]))
                
    parent::__construct([self::tag => $valori[self::tag], self::contenuto => $valori[self::contenuto]]);
            else
                throw new 
    Exception("Occorre definire la proprietà contenuto e tag");
        }

        public function 
    unisci(\iComponenteHTML $contenuto) {
            return new 
    cTag([self::tag => $this->tagself::contenuto => $this $contenuto]);
        }

        public function 
    __toString() {
            return 
    "<$this->tag>" parent::__toString() . "</$this->tag>";
        }

    }

    class 
    cDiv extends cTag {

        public function 
    __construct(array $valori) {
            
    $valori[self::tag] = 'div';
            
    parent::__construct($valori);
        }


    A questo punto il codice d'esempio che è:

    Codice PHP:
    $div1 = new cDiv([cDiv::contenuto => new cStringaHTML([cStringaHTML::contenuto => 'Contenuto del primo <div>.'])]);
    $div2 = new cDiv([cDiv::contenuto => new cStringaHTML([cStringaHTML::contenuto => 'Contenuto del secondo <div>.'])]);

    $div3 $div1->unisci($div2);

    echo 
    $div3
    Tutti e 3 gli oggetti istanziati non possono essere modificati poichè figli di cOggettoCostante.

    La versione che non alloca più istanze per oggetti costanti con stato identico

    A questo punto per completezza ti posto anche la versione che fa uso della classe cOggettoCostante che istanzia un nuovo oggetto solo se lo stato per la classe richiesta non è mai stato utilizzato (quella sparagnina e che ti piace ancora meno). Le classi in gioco sono sempre le stesse di prima, il codice d'altra parte cambia leggermente dovendo le figlie ridefinire i metodi statici crea e istanzia e dovendo il client fare udo dei metodi statici per la creazione degli oggetti:

    Codice PHP:
    <?php

    class cOggettoCostante {

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

        public static function 
    crea(array $valori) {
            
    $hash hash("sha256"serialize($valori)); //tengo le dita incrociate
            
    $class get_called_class();
            if (!isset(
    self::$gliOggetti[$class][$hash]))
                
    self::$gliOggetti[$class][$hash] = static::istanzia($valori);
            return 
    self::$gliOggetti[$class][$hash];
        }

        protected static function 
    istanzia(array $valori) {
            return new 
    OggettoCostante($valori);
        }

        protected 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");
        }

    }

    interface 
    iComponenteHTML {
        public function 
    __toString();
        public function 
    unisci(\iComponenteHTML $contenuto);
    }

    abstract class 
    aContenutoBody extends cOggettoCostante implements iComponenteHTML {

        const 
    contenuto 'contenuto';

        public function 
    __toString() {
            return 
    $this->contenuto;
        }

        abstract public function 
    unisci(\iComponenteHTML $contenuto);

        protected static function 
    verificaContenutoAccettabile($contenuto) {
            return 
    is_string($contenuto) or is_a($contenuto'iComponenteHTML');
        }

    }

    class 
    cStringa extends aContenutoBody {

        public static function 
    crea(array $valori) {
            if (isset(
    $valori[self::contenuto]) and is_string($valori[self::contenuto]))
                return 
    parent::crea([self::contenuto => htmlspecialchars($valori[self::contenuto])]);
            else
                throw new 
    Exception("Occorre definire la proprietà contenuto che sia di tipo stringa");
        }

        protected static function 
    istanzia(array $valori) {
            if (isset(
    $valori[self::contenuto]) and is_string($valori[self::contenuto]))
                return new 
    cStringa($valori);
            throw new 
    Exception("Una stringa HTML deve essere una stringa di testo o contenuto non definito");
        }

        public function 
    unisci(\iComponenteHTML $contenuto) {
            return 
    self::crea([self::contenuto => $this $contenuto]);
        }

    }

    class 
    cTag extends aContenutoBody {

        const 
    tag 'tag';

        public static function 
    crea(array $valori) {
            if (isset(
    $valori[self::contenuto]) and isset($valori[self::tag]) and self::verificaContenutoAccettabile($valori[self::contenuto]))
                return 
    parent::crea([self::tag => $valori[self::tag], self::contenuto => $valori[self::contenuto]]);
            else
                throw new 
    Exception("Occorre definire la proprietà contenuto e tag");
        }

        protected static function 
    istanzia(array $valori) {
            return new 
    cDiv($valori);
        }

        public function 
    unisci(\iComponenteHTML $contenuto) {
            return 
    self::crea([self::tag => $this->tagself::contenuto => $this $contenuto]);
        }

        public function 
    __toString() {
            return 
    "<$this->tag>" parent::__toString() . "</$this->tag>";
        }

    }

    class 
    cDiv extends cTag {

        public static function 
    crea(array $valori) {
            
    $valori[self::tag] = 'div';
            return 
    parent::crea($valori);
        }

        protected static function 
    istanzia(array $valori) {
            return new 
    cDiv($valori);
        }

    }

    $div1 cDiv::crea([cDiv::contenuto => cStringa::crea([cStringa::contenuto => 'Contenuto del primo <div>.'])]);
    $div2 cDiv::crea([cDiv::contenuto => cStringa::crea([cStringa::contenuto => 'Contenuto del secondo <div>.'])]);

    $div3 $div1->unisci($div2);

    echo 
    $div3;
    ?>
    In entrambi i casi l'output prodotto è:
    codice:
    Contenuto del primo <div>.
    Contenuto del secondo <div>.
    
    avente codice HTML
    codice:
    <div><div>Contenuto del primo &lt;div&gt;.</div><div>Contenuto del secondo &lt;div&gt;.</div></div>
    Nota: La classe cOggettoCostante non è completa e dovrebbe definire un metodo uguale(\cOggettoCostante $oggetto) che ci dica se due costanti oggetto definiscono le stesse proprietà con lo stesso valore, oltre ad un metodo proprietaDisponibili() che restituisca l'elenco delle proprietà accessibili in lettura. Sarebbe auspicabile che l'oggetto implementi l'interfaccia arrayAccess in modo che $oggetto->proprieta sia equivalente a $oggetto['proprieta'] semplificando il codice in molti contesti.

    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 © 2026 vBulletin Solutions, Inc. All rights reserved.