Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

creare un hash di qualunque valore

208 views
Skip to first unread message

alex

unread,
Apr 23, 2015, 6:20:55 AM4/23/15
to
md5() crea l'hash di una stringa.
Sarebbe possibile creare anche un hash di un'istanza di una classe, di
un array, ecc.?

fma...@gmail.com

unread,
Apr 23, 2015, 6:29:11 AM4/23/15
to
Risposta corretta ma molto probabilmente non quello che ti serve:
Prima serializzi l'oggetto, poi ti prendi md5.
$hash = md5(serialize($obj));
Dico che probabilmente non è quello che ti serve perché due classi diverse
possono avere lo stesso hash.

Domanda: ma che devi fare??

Ciao!

alex

unread,
Apr 23, 2015, 8:14:31 AM4/23/15
to
controllare se un elemento di un array contiene già lo stesso valore
(stringa, numero, array, oggetto, bool) che si sta per aggiungere
(tramite array_push() oppure $array[]=$valore)

fma...@gmail.com

unread,
Apr 23, 2015, 8:25:33 AM4/23/15
to
cioè in_array()? (o anche un semplice for?)

Se sei preoccupato per le performances perché ne devi fare tanti (e sei
sicuro di stare usando l'algoritmo giusto), puoi usare una hashmap, che in
PHP è.. l'array: inserisci i tuoi dati come chiavi invece che come valori
e controlli con isset().

O magari puoi semplicemente mettere dentro tutto e chiamare array_unique()
alla fine.

Per la migliore soluzione servono altri dettagli, ma di sicuro con questa cosa
degli hash stai andando fuori strada..

Ciao!

alex

unread,
Apr 23, 2015, 9:04:42 AM4/23/15
to
Il 23/04/2015 12:29, fma...@gmail.com ha scritto:
> Dico che probabilmente non è quello che ti serve perché due classi diverse
> possono avere lo stesso hash.

come è possibile?

fma...@gmail.com

unread,
Apr 23, 2015, 9:25:00 AM4/23/15
to
A parte che con gli md5 puoi avere collisioni, e per quanto improbabile sia
non lo rende un metodo viabile.

Detto questo, basta avere due istanze dello stesso oggetto con gli stessi
valori per membri.
class A {
private $i;
public function __construct($i) { $this->i = $i; }
}
$a0 = new A(2);
$a1 = new A(2);
var_dump(md5(serialize($a0))==md5(serialize($a1))); //true

In ogni caso continui a non dire cosa vuoi risolvere. Così non si va molto
lontano.

Ciao!

alex

unread,
Apr 23, 2015, 10:11:40 AM4/23/15
to
Il 23/04/2015 14:25, fma...@gmail.com ha scritto:
> Il giorno giovedì 23 aprile 2015 14:14:31 UTC+2, alex ha scritto:
>> Il 23/04/2015 12:29, fma...@gmail.com ha scritto:
>>> On Thursday, April 23, 2015 at 12:20:55 PM UTC+2, alex wrote:
>>>> md5() crea l'hash di una stringa.
>>>> Sarebbe possibile creare anche un hash di un'istanza di una classe, di
>>>> un array, ecc.?
>>>
>>> Risposta corretta ma molto probabilmente non quello che ti serve:
>>> Prima serializzi l'oggetto, poi ti prendi md5.
>>> $hash = md5(serialize($obj));
>>> Dico che probabilmente non è quello che ti serve perché due classi diverse
>>> possono avere lo stesso hash.
>>>
>>> Domanda: ma che devi fare??
>>
>> controllare se un elemento di un array contiene già lo stesso valore
>> (stringa, numero, array, oggetto, bool) che si sta per aggiungere
>> (tramite array_push() oppure $array[]=$valore)
>>
>
> cioè in_array()? (o anche un semplice for?)
>

in_array() funziona solo con stringa/numero; con un oggetto restituisce
sempre true.

> Se sei preoccupato per le performances perché ne devi fare tanti (e sei
> sicuro di stare usando l'algoritmo giusto), puoi usare una hashmap, che in
> PHP è.. l'array: inserisci i tuoi dati come chiavi invece che come valori
> e controlli con isset().
>

forse è la soluzione, anche se non ho capito totalmente quello che intenti

> O magari puoi semplicemente mettere dentro tutto e chiamare array_unique()
> alla fine.
>

array_unique() rimuove semplicemente i duplicati, ma non segnala, prima
dell'aggiunta, un valore già presente, o sbaglio?
Agisce a posteriori, mi sembra...

> Per la migliore soluzione servono altri dettagli, ma di sicuro con questa cosa
> degli hash stai andando fuori strada..

class a {
private $abc;

function __construct($abc) {
$this->abc=$abc;
}
}

$arr=array();
array_push($arr,1);//ok
array_push($arr,1);//duplicato
array_push($arr,new a(1));//ok
array_push($arr,new a(2));//ok
array_push($arr,new a(2));//duplicato

Per impedire l'aggiunta dei duplicati?

alex

unread,
Apr 23, 2015, 10:19:28 AM4/23/15
to
Il 23/04/2015 15:24, fma...@gmail.com ha scritto:
> var_dump(md5(serialize($a0))==md5(serialize($a1))); //true
>

if (serialize($a0)==serialize($a1))
throw new Exception('valore già esistente');

Penso che questa sia la soluzione

> In ogni caso continui a non dire cosa vuoi risolvere. Così non si va molto
> lontano.

leggi l'altro post, ma come già detto, forse ho trovato la soluzione

alex

unread,
Apr 23, 2015, 10:23:03 AM4/23/15
to
Il 23/04/2015 16:19, alex ha scritto:
>
> if (serialize($a0)==serialize($a1))
> throw new Exception('valore già esistente');

...naturalmente da inserire in un ciclo for

fma...@gmail.com

unread,
Apr 23, 2015, 10:32:18 AM4/23/15
to
Il giorno giovedì 23 aprile 2015 16:11:40 UTC+2, alex ha scritto:
> class a {
> private $abc;
>
> function __construct($abc) {
> $this->abc=$abc;
> }
> }
>
> $arr=array();
> array_push($arr,1);//ok
> array_push($arr,1);//duplicato
> array_push($arr,new a(1));//ok
> array_push($arr,new a(2));//ok
> array_push($arr,new a(2));//duplicato
>
> Per impedire l'aggiunta dei duplicati?

Se due istanze differenti per te sono uguali se hanno gli stessi membri,
allora basta che fai:

$arr = array();
$arr[serialize($obj0)] = $obj0;
$arr[serialize($obj1)] = $obj1;
etc.

Non serve controllare perché tanto per te due oggetti uguali sono uguali,
che t'importa qual'è?

(non prendo in considerazione l'array con valori misti int/stringhe/oggetti
per ovvi motivi)

Ciao!

fma...@gmail.com

unread,
Apr 23, 2015, 10:43:52 AM4/23/15
to
In ogni caso una soluzione più "normale" sarebbe indicizzare la tua classe
secondo qualche parametro, visto che non ti serve tutta la serializzazione in
ogni caso, magari usando un metodo (o __toString() se sei pigro) per avere
l'indice.

In una situazione ancora più normale, quello che chiedi non succede di farlo
praticamente mai, ma visto fai il misterioso chissà.

Ciao!

alex

unread,
Apr 23, 2015, 11:22:00 AM4/23/15
to
Il 23/04/2015 16:32, fma...@gmail.com ha scritto:
> Se due istanze differenti per te sono uguali se hanno gli stessi membri,
> allora basta che fai:
>
> $arr = array();
> $arr[serialize($obj0)] = $obj0;
> $arr[serialize($obj1)] = $obj1;
> etc.
>
> Non serve controllare perché tanto per te due oggetti uguali sono uguali,
> che t'importa qual'è?

è sempre bene capire se, un valore è uguale (è già stato aggiunto), e
quindi perchè è stato, o meglio, sta per essere aggiunto una seconda volta.
Lasciare che il tutto avvenga in silenzio (almeno un warning ci vuole)
non è una cosa buona

fma...@gmail.com

unread,
Apr 23, 2015, 12:18:29 PM4/23/15
to
Se sapessi di cosa stiamo parlando ti potrei forse dare ragione o torto, così
boh, lo saprai te che devi fare.

Ciao!

alex

unread,
Apr 23, 2015, 3:29:45 PM4/23/15
to
Il 23/04/2015 18:18, fma...@gmail.com ha scritto:
> Se sapessi di cosa stiamo parlando ti potrei forse dare ragione o torto, così
> boh, lo saprai te che devi fare.

class Collezione{
static $arr=array();

static function add($value){
array_push(self::$arr, $value);
}
}

Collezione::add(123);

poi da qualche altra parte del proggetto

Collezione::add(123);

poi da qualche altra parte del proggetto

Collezione::add(123);

poi da qualche altra parte del proggetto

Collezione::add(123);

poi da qualche altra parte del proggetto

Collezione::add(123);

poi da qualche altra parte del proggetto

Collezione::add(123);

A questo punto viene il dubbio... serve d'avvero aggiungere per 6-7
volte sempre lo stesso valore?
Forse no...
Forse, per distrazione, si stanno facendo degli adding inutili...
... che tra l'altro appesantiscono l'applicazione.
Quindi non è il caso di implementare qualche controllo, in modo che il
programmatore si accorga che c'è un po' di sporcizia (adding inutili), e
quindi fare un po' di pulizia?

fma...@gmail.com

unread,
Apr 23, 2015, 3:45:18 PM4/23/15
to
Oh, manco con le pinze, eh? Non eri te che dicevi che bisognava chiedere,
chiedere, chiedere.. ? :D Così però esageri!

Da come l'hai posta boh, non si può sapere. Quanti inserimenti sono in totale?
Cosa si sta inserendo? Che succede se ci sono duplicati? I duplicati vanno
contati, scartati o mandano tutto in eccezione? Cosa sono tutte queste
parti che fanno add ognuna per conto suo? Cos'è 'sta collezione? Perché è
statica?
Ma soprattutto: cosa-cacchio-rappresentano-sti-dati?

Non puoi fare una domanda di modellazione software senza dire cosa vuoi
modellare.

Ciao!

Alessandro Pellizzari

unread,
Apr 24, 2015, 12:16:23 AM4/24/15
to
Il Thu, 23 Apr 2015 21:29:42 +0200, alex ha scritto:

> Quindi non è il caso di implementare qualche controllo, in modo che il
> programmatore si accorga che c'è un po' di sporcizia (adding inutili), e
> quindi fare un po' di pulizia?

In generale no.

Se il programmatore sta aggiungendo sempre la stessa cosa all'array o sa
quello che fa (che sarebbe il suo lavoro) o ha sbagliato architettura.

Non puoi imporre a un programmatore l'architettura generale della sua
applicazione.

Soprattutto quando la tua stessa libreria sta ignorando completamente le
regole basilari della programmazione, ma spero fosse solo un esempio per
fare presto.

Bye.

alex

unread,
Apr 24, 2015, 4:55:33 AM4/24/15
to
Il 23/04/2015 21:45, fma...@gmail.com ha scritto:
> Da come l'hai posta boh, non si può sapere. Quanti inserimenti sono in totale?

La domanda sarebbe: non è meglio prevenire dall'inizio l'inserimento di
valori duplicati/rindondanti che potrebbero provenire anche da altre
risorse, tipo file yaml?
Io direi di si, ed ho trovato anche la soluzione (anche grazie a te); tu
però mi continui a brontolare :D

> Cosa si sta inserendo?

dati per impostare alcuni aspetti su come deve essere eseguita l'app.
Alcuni di questi dati (impostazioni) si possono modificare anche da file
di configurazione yaml.

> Che succede se ci sono duplicati?

non dovrebbe succedere niente, ma ritengo che sia meglio evitare
l'eventuale propagazione di valori rindondanti.
Parlo soprattutto per l'utente che andrà ad usare l'app: non è meglio
avvertirlo che ha specificato due o più volte lo stesso valore?
Quale dei due valori usare effettivamente?
Quello ad esempio specificato tramite codice php, o quello impostato
tramite file di configurazione?

Non è meglio informare l'utente (un po' distratto) che si è creato un
piccolo conflitto?

> Cos'è 'sta collezione?

è una collezione globale di dati (impostazioni, settings) che vanno ad
influire sul funzionamento dell'app; l'ho già detto.

> Perché è statica?

perchè è una collezione globale di dati (impostazioni, settings) che
vanno ad influire A LIVELLO GENERALE (GLOBALE) sul funzionamento dell'app.
L'ho già detto, lo ripeto e lo ridico.

E poi non è meglio istanziare le classi solo quando serve?
Me l'ha detto proprio uno di voi, in un'altra discussione, che è sempre
meglio preferire classi con metodi statici

> Ma soprattutto: cosa-cacchio-rappresentano-sti-dati?
>

guarda che sono già arrabbiato, quindi stai attento :D


fma...@gmail.com

unread,
Apr 24, 2015, 6:26:53 AM4/24/15
to
Oh, ora è più chiaro! Non c'è bisogno che t'arrabbi, riconoscerai che questa
situazione c'entra ben poco con quello che avevi chiesto all'inizio, non ti
pare?
Comunque, questo è un caso più che comune: un'applicazione che prende la
configurazione da un file utente, altrimenti gira con i valori di default.

Come prima cosa l'array della configurazione ha sulle chiavi solo stringhe,
per cui non capisco perché cercavi un modo di serializzare degli oggetti.
Oltretutto non devi avvertire l'utente: se mette un valore nella sua
configurazione è perché vuole sovrascrivere il valore di default, è il
comportamento atteso.

A meno che non devi fare operazioni complesse sul parsing, e visto che l'utente
scrive in yaml, basta che scrivi a tua volta i valori di default in un file
yaml, e poi unisci gli array sovrascrivendo il default con i valori utenti,
se presenti.

$defaultConfiguration = yaml_parse_file("default.yaml");
$userConfiguration = yaml_parse_file("user.yaml");
$configuration = array_merge($defaultConfiguration, $userConfiguration);

Così è come fanno la quasi totalità delle applicazioni, e quindi è quello
che un utente credo s'aspetti.

Ciao!

alex

unread,
Apr 24, 2015, 6:35:19 AM4/24/15
to
Il 24/04/2015 06:16, Alessandro Pellizzari ha scritto:
> Il Thu, 23 Apr 2015 21:29:42 +0200, alex ha scritto:
>
>> Quindi non è il caso di implementare qualche controllo, in modo che il
>> programmatore si accorga che c'è un po' di sporcizia (adding inutili), e
>> quindi fare un po' di pulizia?
>
> In generale no.
>
> Se il programmatore sta aggiungendo sempre la stessa cosa all'array o sa
> quello che fa (che sarebbe il suo lavoro) o ha sbagliato architettura.
>

certo, però non può tenere sempre e tutto sotto controllo.
Quindi qualche controllo non fa mai male.
In caso contrario tanto vale abolire i validator, il type-hinting, i
metodi ad accesso protected, tanto il programmatore sa quello che fa...

> Non puoi imporre a un programmatore l'architettura generale della sua
> applicazione.
>

non sto parlando di imporre architetture, ma implementare un minimo di
checking per avvertirlo che sta facendo qualcosa che in futuro potrebbe
crearli problemi...
È reato?

alex

unread,
Apr 24, 2015, 12:52:30 PM4/24/15
to
Il 24/04/2015 12:26, fma...@gmail.com ha scritto:


Prima di tutto
http://www.filedropper.com/buioluce_1
decomprimi in una dir del tuo web-server, e dal browser lancia index.php

Io preferisco lavorare con la luce, cmq buona visione!!!


> Oh, ora è più chiaro! Non c'è bisogno che t'arrabbi, riconoscerai che questa
> situazione c'entra ben poco con quello che avevi chiesto all'inizio, non ti
> pare?

Ah si?

DirectoryGroup.php:11 - Al posto di serialize cosa avresti usato?

> Comunque, questo è un caso più che comune: un'applicazione che prende la
> configurazione da un file utente, altrimenti gira con i valori di default.
>
> Come prima cosa l'array della configurazione ha sulle chiavi solo stringhe,
> per cui non capisco perché cercavi un modo di serializzare degli oggetti.

veramente parlavo di *dati* in generale...
Ok, ho tirato fuori il discorso della configurazione per fare un
esempio, non molto azzeccato in effetti :P

Alessandro Pellizzari

unread,
Apr 24, 2015, 2:52:51 PM4/24/15
to
Il Fri, 24 Apr 2015 10:55:28 +0200, alex ha scritto:

> La domanda sarebbe: non è meglio prevenire dall'inizio l'inserimento di
> valori duplicati/rindondanti che potrebbero provenire anche da altre
> risorse, tipo file yaml?

No.

> dati per impostare alcuni aspetti su come deve essere eseguita l'app.
> Alcuni di questi dati (impostazioni) si possono modificare anche da file
> di configurazione yaml.

Se sono impostazioni avranno una chiave. Una volta che hai una chiave è
facile che sia univoca.

In particolare i file YAML sono chiave:valore.

> Parlo soprattutto per l'utente che andrà ad usare l'app: non è meglio
> avvertirlo che ha specificato due o più volte lo stesso valore?

No.

> Quale dei due valori usare effettivamente?

Quello che hai scritto nella documentazione.
Se gli dici "lo YAML ha priorità sui parametri nel bootstrap.php" poi
devi accertarti che il tuo codice rispetti quello che hai scritto.

> Non è meglio informare l'utente (un po' distratto) che si è creato un
> piccolo conflitto?

Se l'utente è abbastanza distratto da scrivere due volte lo stesso
valore, è anche abbastanza distratto da dimenticare un punto decimale o
un tabulatore nel file YAML.

Non puoi prevedere tutti i modi possibili in cui un programmatore può
inserire bug, e verificare che non inserisca due volte la stessa cosa in
un file di config mi sembra la più inutile da controllare, onestamente.

>> Cos'è 'sta collezione?
>
> è una collezione globale di dati (impostazioni, settings) che vanno ad
> influire sul funzionamento dell'app; l'ho già detto.

Dove l'hai detto? Qualche riga più su? E ti lamenti se la gente non l'ha
ancora letto?

> > Perché è statica?
>
> perchè è una collezione globale di dati (impostazioni, settings) che
> vanno ad influire A LIVELLO GENERALE (GLOBALE) sul funzionamento
> dell'app.
> L'ho già detto, lo ripeto e lo ridico.

Non è che leggiamo in tempo reale quello che stai scrivendo, eh.
Datti una calmata.

> E poi non è meglio istanziare le classi solo quando serve?

No.

> Me l'ha detto proprio uno di voi, in un'altra discussione, che è sempre
> meglio preferire classi con metodi statici

O hai letto male o hai capito male o ti hanno detto male.
Non è quasi mai preferibile usare classi con metodi statici.

In questo caso può essere tollerabile, ma allora chiamala almeno
Configurazione, non Collezione, e usa indici.

Bye.

Alessandro Pellizzari

unread,
Apr 24, 2015, 3:02:48 PM4/24/15
to
Il Fri, 24 Apr 2015 12:35:11 +0200, alex ha scritto:

> certo, però non può tenere sempre e tutto sotto controllo.

Il lavoro del programmatore è tenere tutto sotto controllo.

Il lavoro di chi scrive librerie è di rendere queste librerie facili da
usare, e le classi abbastanza piccole e mirate da consentire al
programmatore di tenere a mente cosa fanno senza confondersi.

Per esempio, nel tuo caso, ti basta avere un metodo

add($key, $value)

che aggiunga un valore a una chiave (che quindi rappresenta un sub-array)
e un metodo

set($key, $value)

che invece sovrascrive la chiave col valore.

Così il programmatore vede subito cosa sta facendo.

> Quindi qualche controllo non fa mai male.

Mai detto che i controlli facciano male.
Dico che questo controllo fa male.
Se hai un array di un centinaio di elementi prensi dal codice e ne
aggiungi un altro centinaio presi da YAML, stai facendo 10.000 md5 e
altrettanti serialize ad ogni pagina che viene visitata.

Quando potresti facilmente usare array_key_exist() che è O(1) perché è
una funzione di hashing, e farne al massimo 100.

> In caso contrario tanto vale abolire i validator, il type-hinting, i
> metodi ad accesso protected, tanto il programmatore sa quello che fa...

I validator non sono automatici. È il programmatore a decidere quando
usarli.
Il type-hinting... ha appena generato una flame epocale nella mailing
list del core PHP, ma in generale IMHO sono utili se programmi a contratto
(quindi con interfacce fatte bene) e con una certa architettura, ma sono
anche discrete pigne in culo in altri casi (ecco il motivo della flame).

I metodi protected... ogni tanto provo a usarli, e puntualmente mi ritrovo
a rimetterli public, così almeno li posso testare senza fare
introspezione. Poi, se proprio proprio non voglio che l'utente li chiami,
ci metto un docblock con scritto "Non usate questo metodo". :P

> non sto parlando di imporre architetture, ma implementare un minimo di
> checking per avvertirlo che sta facendo qualcosa che in futuro potrebbe
> crearli problemi...
> È reato?

Non è reato. È pura utopia.

YAGNI. Non puoi prevedere il futuro. Programma per il presente. Per il
futuro c'è il refactoring (che è molto difficile se usi classi statiche).

Bye.

fma...@gmail.com

unread,
Apr 24, 2015, 4:52:40 PM4/24/15
to
On Friday, April 24, 2015 at 6:52:30 PM UTC+2, alex wrote:
> Il 24/04/2015 12:26, fma...@gmail.com ha scritto:
>
> http://www.filedropper.com/buioluce_1
>
> DirectoryGroup.php:11 - Al posto di serialize cosa avresti usato?
>

Allora: seguimi perché probabilmente questo sarà un post lungo :)
Cerco di tenerlo il più corto possibile, ma probabilmente sarà comunque una
bella sleppa di testo..

Prima di tutto, sto scrivendo male quello che puoi trovare in un sacco di
libri storici che *devi* leggere se vuoi fare questo lavoro. Primo fra tutti
uno che già t'ho citato qualche settimana fa, ma ti posto direttamente un link
per prendertelo da amazon: http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented-ebook/dp/B000SEIBB8
Puoi chiedere qui o su qualsiasi altro NG di programmazione, stai sicuro che
tutti ne hanno una copia a casa.

Vediamo:

Uno, nello specifico, non avrei usato niente, visto che alla fine di tutta la
pantomima devi solo fare una mkdir: avrei chiamato quella e basta, senza
alcun tipo di classe. Non c'è motivo di astrarre una funzione che è garantita
essere parte del core.

Due, sulla cosa static o no. Il concetto è facile (il che non vuol dire che
sia facile capire quando applicarlo o no, ma questa è un'altra storia):
se una classe non mantiene alcuno stato allora può essere statica.
Che vuol dire avere uno stato? Significa che i suoi metodi, quando richiamati,
usano, oltre ad i parametri passati, anche "altre cose", memorizzate da
qualche parte.
Esempi:
- l'array con la configurazione è chiaramente un concetto a se stante, e
decidi di avere una classe che la gestisce. Vuoi un metodo "prendi()" che
ritorna la configurazione e un "aggiungiValore(k,v)" che prende una coppia
chiave/valore e l'aggiunge alla configurazione. Chiaramente questa classe ha
uno stato: la configurazione attuale.
- ogni volta che crei un file o una cartella vuoi fare log su file o su
database: decidi di usare una classe con due metodi "creaFile" e "creaCartella"
per gestire la cosa. Questi due metodi non hanno bisogno di nessun'altra
informazione se non il nome del file o della cartella, per cui possono essere
statici. (o magari il nome del file su cui fare log è uno stato? :) esercizio
per il lettore).

Tre, mettiamo il caso che avevi classi non statiche (per l'esempio che hai
postato, immaginiamo che la classe che creava le directory lo faceva solo
sulla scrittura di un file, altrimenti, se nessuno ci metteva files dentro,
rimaneva una directory "virtuale" e non sarebbe stata creata per nulla - so che
l'esempio è stiracchiato, ma seguimi). In questo caso, a livello
architetturale, cosa volevi? Volevi un'instanza di DirectoryMaker unica per
ogni tipo di parametro passato al costruttore: un nome di cartella virtuale.
C'è un pattern famoso per questa situazione (o meglio, è famoso perché c'è un
"errore architetturale" famoso che vien fuori da situazioni simili che spingono
l'utilizzo di singleton, ma sto divagando): il factory. L'avrai sentito,
immagino ;) Fai una classe che si occupa di costruire le classi che gestiscono
le directory virtuali e, in questo caso, che fanno cache delle istanze già
esistenti che possono già fare il lavoro richiesto.
So che può sembrare complesso, ma in pratica è abbastanza banale, basta che fai
due prove e te ne rendi conto subito da solo.

Mi rendo conto che magari ho buttato troppa carne al fuoco tutt'insieme, per
questo spero che tu ti legga, oltre al il libro che ti ho suggerito (insisto
perché, sul serio, personalmente non son mai riuscito a concepire un
programmatore che non conosca le basi dei pattern più comuni), molte più cose
sulla modellazione software.

Ciao!

alex

unread,
Apr 25, 2015, 12:52:38 AM4/25/15
to
Il 24/04/2015 20:52, Alessandro Pellizzari ha scritto:
>> >Non è meglio informare l'utente (un po' distratto) che si è creato un
>> >piccolo conflitto?
> Se l'utente è abbastanza distratto da scrivere due volte lo stesso
> valore, è anche abbastanza distratto da dimenticare un punto decimale o
> un tabulatore nel file YAML.
>

si si, ma l'importante è che riesca a capire dove e cosa ha sbagliato
(se il codice non è ben fatto, potrebbe avere delle difficoltà).
Tutti possiamo avere delle sviste...

> Non puoi prevedere tutti i modi possibili in cui un programmatore può
> inserire bug, e verificare che non inserisca due volte la stessa cosa in
> un file di config mi sembra la più inutile da controllare, onestamente.
>

dipende, e cmq lo stesso valore potrebbe essere presente in due file
diversi...
Prevedere tutto no, ma qualcosa (tramite dei semplici checking) si può
fare...

>>> >>Cos'è 'sta collezione?
>> >
>> >è una collezione globale di dati (impostazioni, settings) che vanno ad
>> >influire sul funzionamento dell'app; l'ho già detto.
> Dove l'hai detto? Qualche riga più su? E ti lamenti se la gente non l'ha
> ancora letto?
>

????

>> > > Perché è statica?
>> >
>> >perchè è una collezione globale di dati (impostazioni, settings) che
>> >vanno ad influire A LIVELLO GENERALE (GLOBALE) sul funzionamento
>> >dell'app.
>> >L'ho già detto, lo ripeto e lo ridico.
> Non è che leggiamo in tempo reale quello che stai scrivendo, eh.
> Datti una calmata.
>
>> >E poi non è meglio istanziare le classi solo quando serve?
> No.
>

http://www.newswebreader.com/it.comp.www.php/Re-funzioni-o-metodi/5686
Ti cito l'ultima parte:
"Per ora, se sei in-a-hurry per una soluzione, usa solo classi (sempre sotto
namespace, se non portano uno stato solo con metodi statici, senza derivare
se non sono strettamente in una relazione IS-A, cercando di non disegnare in
modo che sia necessario un ovverride) almeno che non si tratti di uno
script,
dove devi scrivere procedurale."

>> >Me l'ha detto proprio uno di voi, in un'altra discussione, che è sempre
>> >meglio preferire classi con metodi statici
> O hai letto male o hai capito male o ti hanno detto male.
> Non è quasi mai preferibile usare classi con metodi statici.
>

come sopra; poi dipende dai punti di vista


Alessandro Pellizzari

unread,
Apr 25, 2015, 2:00:37 AM4/25/15
to
Il Sat, 25 Apr 2015 06:52:33 +0200, alex ha scritto:

> http://www.newswebreader.com/it.comp.www.php/Re-funzioni-o-metodi/5686
> Ti cito l'ultima parte:
> "Per ora, se sei in-a-hurry per una soluzione, usa solo classi (sempre
> sotto namespace, se non portano uno stato solo con metodi statici, senza
> derivare se non sono strettamente in una relazione IS-A, cercando di non
> disegnare in modo che sia necessario un ovverride) almeno che non si
> tratti di uno script,
> dove devi scrivere procedurale."

E tu, di tutto il discorso, hai letto solo "solo con metodi statici"?

La prima riga dice "Per ora, se sei in-a-hurry". Che, tradotto,
significa: se non hai tempo per fare una cosa fatta bene ma hai bisogno
di risultati subito, inizia con una cosa fatta male, ma almeno dalle una
struttura decente.

Ma implica che poi, più avanti, avresti imparato come farla bene.

Quello che ti ha suggerito in quel messaggio è che, piuttosto che usare
funzioni globali per fare progetti grossi, è meglio almeno raggrupparle
in classi con metodi statici.

Non certo che devi sempre usare metodi statici, anzi.

Bye.

alex

unread,
Apr 25, 2015, 4:09:31 AM4/25/15
to
Il 25/04/2015 08:00, Alessandro Pellizzari ha scritto:
> E tu, di tutto il discorso, hai letto solo "solo con metodi statici"?
>
> La prima riga dice "Per ora, se sei in-a-hurry". Che, tradotto,
> significa: se non hai tempo per fare una cosa fatta bene ma hai bisogno
> di risultati subito, inizia con una cosa fatta male, ma almeno dalle una
> struttura decente.
>
> Ma implica che poi, più avanti, avresti imparato come farla bene.
>
> Quello che ti ha suggerito in quel messaggio è che, piuttosto che usare
> funzioni globali per fare progetti grossi, è meglio almeno raggrupparle
> in classi con metodi statici.
>
> Non certo che devi sempre usare metodi statici, anzi.

certamente, ma è altrettanto consigliato *non* istanziare le classi
quando *non* serve.

class abc{
static function sum($a, $b) { return $a+$b; }
}

In questo caso, secondo te è proprio indispensabile istanziare?

alex

unread,
Apr 25, 2015, 4:35:13 AM4/25/15
to
Il 24/04/2015 22:52, fma...@gmail.com ha scritto:
> Uno, nello specifico, non avrei usato niente, visto che alla fine di tutta la
> pantomima devi solo fare una mkdir: avrei chiamato quella e basta, senza
> alcun tipo di classe. Non c'è motivo di astrarre una funzione che è garantita
> essere parte del core.
>

hai ragione, ma il directory-making te l'ho proposto solo come esempio.
Ci sono altri casi in cui gli oggetti (istanze) bisogna usarli per forza

> Due, sulla cosa static o no. Il concetto è facile (il che non vuol dire che
> sia facile capire quando applicarlo o no, ma questa è un'altra storia):
> se una classe non mantiene alcuno stato allora può essere statica.
> Che vuol dire avere uno stato? Significa che i suoi metodi, quando richiamati,
> usano, oltre ad i parametri passati, anche "altre cose", memorizzate da
> qualche parte.
> Esempi:
> - l'array con la configurazione è chiaramente un concetto a se stante, e
> decidi di avere una classe che la gestisce. Vuoi un metodo "prendi()" che
> ritorna la configurazione e un "aggiungiValore(k,v)" che prende una coppia
> chiave/valore e l'aggiunge alla configurazione. Chiaramente questa classe ha
> uno stato: la configurazione attuale.
> - ogni volta che crei un file o una cartella vuoi fare log su file o su
> database: decidi di usare una classe con due metodi "creaFile" e "creaCartella"
> per gestire la cosa. Questi due metodi non hanno bisogno di nessun'altra
> informazione se non il nome del file o della cartella, per cui possono essere
> statici. (o magari il nome del file su cui fare log è uno stato?:) esercizio
> per il lettore).
>

pienamente d'accordo, l'ho spiegato anche ad Alessandro Pellizzari,
anche se a lui forse piace particolarmente istanziare :D

> Tre, mettiamo il caso che avevi classi non statiche (per l'esempio che hai
> postato, immaginiamo che la classe che creava le directory lo faceva solo
> sulla scrittura di un file, altrimenti, se nessuno ci metteva files dentro,
> rimaneva una directory "virtuale" e non sarebbe stata creata per nulla - so che
> l'esempio è stiracchiato, ma seguimi).

si

> In questo caso, a livello
> architetturale, cosa volevi? Volevi un'instanza di DirectoryMaker unica per
> ogni tipo di parametro passato al costruttore: un nome di cartella virtuale.
> C'è un pattern famoso per questa situazione (o meglio, è famoso perché c'è un
> "errore architetturale" famoso che vien fuori da situazioni simili che spingono
> l'utilizzo di singleton, ma sto divagando): il factory. L'avrai sentito,
> immagino;) Fai una classe che si occupa di costruire le classi che gestiscono
> le directory virtuali e, in questo caso, che fanno cache delle istanze già
> esistenti che possono già fare il lavoro richiesto.
> So che può sembrare complesso, ma in pratica è abbastanza banale, basta che fai
> due prove e te ne rendi conto subito da solo.
>

certamente

> Mi rendo conto che magari ho buttato troppa carne al fuoco tutt'insieme, per
> questo spero che tu ti legga, oltre al il libro che ti ho suggerito (insisto
> perché, sul serio, personalmente non son mai riuscito a concepire un
> programmatore che non conosca le basi dei pattern più comuni), molte più cose
> sulla modellazione software.

ok!!!

alex

unread,
Apr 25, 2015, 5:11:46 AM4/25/15
to
Il 24/04/2015 21:02, Alessandro Pellizzari ha scritto:
> Il Fri, 24 Apr 2015 12:35:11 +0200, alex ha scritto:
>
>> certo, però non può tenere sempre e tutto sotto controllo.
>
> Il lavoro del programmatore è tenere tutto sotto controllo.
>

insomma, quando si può.
Ci si può concentrare solo su un aspetto per volta; non ci si può
ricordare di tutto quello che fanno tutte le funzioni dell'app che,
ribadisco, devono essere ben scritte per evitare danni, dovuti ad una
banale distrazione.
Siamo umani!!!

> Il lavoro di chi scrive librerie è di rendere queste librerie facili da
> usare, e le classi abbastanza piccole e mirate da consentire al
> programmatore di tenere a mente cosa fanno senza confondersi.
>

giusto

> Per esempio, nel tuo caso, ti basta avere un metodo
>
> add($key, $value)
>
> che aggiunga un valore a una chiave (che quindi rappresenta un sub-array)
> e un metodo
>

????
aggiunge un valore ad una chiave? Forse ad un array...
...e un metodo?!?!?
Forse hai scritto male la frase :D

> set($key, $value)
>
> che invece sovrascrive la chiave col valore.
>

si

>> Quindi qualche controllo non fa mai male.
>
> Mai detto che i controlli facciano male.
> Dico che questo controllo fa male.
> Se hai un array di un centinaio di elementi prensi dal codice e ne
> aggiungi un altro centinaio presi da YAML, stai facendo 10.000 md5 e
> altrettanti serialize ad ogni pagina che viene visitata.
>
> Quando potresti facilmente usare array_key_exist() che è O(1) perché è
> una funzione di hashing,

si, non volevo controllare l'esistenza della chiave, ma del valore

> e farne al massimo 100.
>

????
100 di che cosa?
:D

> I metodi protected... ogni tanto provo a usarli, e puntualmente mi ritrovo
> a rimetterli public, così almeno li posso testare senza fare
> introspezione.

si può usare un sistema di eventi come quello di Symfony o CakePhp, e
agganciare degli appositi ascoltatori, ma solo in modalità di testing.
Dipende da cosa vuoi fare e cosa intendi per introspezione

> Poi, se proprio proprio non voglio che l'utente li chiami,
> ci metto un docblock con scritto "Non usate questo metodo". :P
>

è meglio anche mettere un underscore prima del nome della funzione.
Oppure, come già detto, valuterei l'utilizzo degli ascoltatori

>> non sto parlando di imporre architetture, ma implementare un minimo di
>> checking per avvertirlo che sta facendo qualcosa che in futuro potrebbe
>> crearli problemi...
>> È reato?
>
> Non è reato. È pura utopia.
>

bah dipende

> YAGNI. Non puoi prevedere il futuro.

il futuro per intero no (sfida disumana), ma qualche situazione comune, si

> Programma per il presente. Per il
> futuro c'è il refactoring (che è molto difficile se usi classi statiche).

beh il refactoring è quasi un'operazione di routine


Alessandro Pellizzari

unread,
Apr 25, 2015, 8:23:53 AM4/25/15
to
Il Sat, 25 Apr 2015 10:09:28 +0200, alex ha scritto:

> certamente, ma è altrettanto consigliato *non* istanziare le classi
> quando *non* serve.
>
> class abc{
> static function sum($a, $b) { return $a+$b; }
> }
>
> In questo caso, secondo te è proprio indispensabile istanziare?

Questo è un caso limite, ma in generale dipende.

Se domani vuoi usare una classe diversa ma con la stessa funzione?

Per esempio, una che supporta la somma tra numeri immaginari. Ti tocca
cercare tutte le chiamate statiche nel tuo codice e cambiarle con la
chiamata alla nuova classe.

Anche il mio è un esempio estremo, mi rendo conto, e viola parzialmente
lo YAGNI (ma è più SOLID), ma con questo tipo di esempi è difficile fare
controesempi.

Bye.

alex

unread,
Apr 25, 2015, 8:56:24 AM4/25/15
to
Il 25/04/2015 14:23, Alessandro Pellizzari ha scritto:
> Il Sat, 25 Apr 2015 10:09:28 +0200, alex ha scritto:
>
>> certamente, ma è altrettanto consigliato *non* istanziare le classi
>> quando *non* serve.
>>
>> class abc{
>> static function sum($a, $b) { return $a+$b; }
>> }
>>
>> In questo caso, secondo te è proprio indispensabile istanziare?
>
> Questo è un caso limite, ma in generale dipende.
>
> Se domani vuoi usare una classe diversa ma con la stessa funzione?
>

ClasseDiversa::sum();
La uso, qual'è il problema?

> Per esempio, una che supporta la somma tra numeri immaginari. Ti tocca
> cercare tutte le chiamate statiche nel tuo codice e cambiarle con la
> chiamata alla nuova classe.
>

????
Chiedo scusa, ma avrai già intuito che a volte faccio fatica a seguirti.
Certo tu (ma anche gli altri) mi stai facendo notare delle cose molto
interessanti, ma se non cerchi di esprimerti con un po' di chiarezza,
non riesco a centrare pienamente il concetto


Alessandro Pellizzari

unread,
Apr 25, 2015, 11:31:24 AM4/25/15
to
Il Sat, 25 Apr 2015 14:56:21 +0200, alex ha scritto:

>> Se domani vuoi usare una classe diversa ma con la stessa funzione?
>>
>>
> ClasseDiversa::sum();
> La uso, qual'è il problema?

Che se la usi in 1000 file diversi te la devi andare a cercare ovunque.

>> Per esempio, una che supporta la somma tra numeri immaginari. Ti tocca
>> cercare tutte le chiamate statiche nel tuo codice e cambiarle con la
>> chiamata alla nuova classe.

> Chiedo scusa, ma avrai già intuito che a volte faccio fatica a seguirti.
> Certo tu (ma anche gli altri) mi stai facendo notare delle cose molto
> interessanti, ma se non cerchi di esprimerti con un po' di chiarezza,
> non riesco a centrare pienamente il concetto

bootstrap.php

$app = new App();
$app->set('somma', new Sommante());

$qualcosa = new Qualcosa($app);
$somma = $qualcosa->fai(10, 20);
...

Qualcosa.php (e altri 1000 file):

class Qualcosa {
public function __construct(App $app)
{
$this->app = $app;
}

public function fai($a, $b) {
$res = $this->app->get('somma')->sum($a, $b);
}
}


Un domani...

class SommanteImmaginario {
public function sum($a, $b) {
if ($a instanceof ImgNumber && $b instanceof ImgNumber) {
// fai la somma tra immaginari
} else {
return $a + $b
}
}
}

modifiche al tuo codice: 1, in bootstrap.php

$app->set('somma', new SommanteImmaginario());

Questo si chiama Dependency Injection (DI). Inietti un oggetto di classe
App in altre classi, e lui fa da Dependency Injection Container (DIC)
tenendo una qualsivoglia copia di Sommante e fornendola a chi la richiede.


Ma spingiamoci oltre:

interface Sommabile {
public function sum($a, $b);
}

class Sommante implements Sommabile { ... }

class SommanteImmaginario implements Sommabile {
public $orig = null;
public function __construct(Sommabile $originale) {
$this->orig = $originale;
}

public function sum($a, $b) {
if ($a instanceof ImgNumber && $b instanceof ImgNumber) {
// fai la somma tra immaginari
} else {
return $this->orig->sum($a, $b);
}
}
}

Il tuo bootstrap diventerà:

$app->set('somma', new SommanteImmaginario(new Sommante()));

Questo si chiama Decoratore, e si usa solitamente con la DI di cui sopra.
Programmi a contratto (l'interface Sommabile, che garantisce di avere una
funzione sum che prende due parametri). A questo punto che tu passi
Sommante o SommanteImmaginario non fa differenza, perché poi lui si
aspetta un Sommabile. SommanteImmaginario è un Sommabile che accetta un
altro Sommabile da wrappare/decorare. Puoi metterne quanti ne vuoi nel
bootstrap, e il resto del codice (se rispetta il contratto) non avrà
nessun problema a gestirlo.

Queste cose semplicemente non le puoi fare con le classi statiche.

Puoi avere la tentazione di usare App come statica, e per progetti medio-
piccoli ci sta e lo faccio anche io. Difficilmente cambierà la struttura
portante dell'applicazione, e se cambia faccio prima a riscrivere
l'applicazione che a fare refactoring di tutto.

Ma, per fare l'esempio del tuo configuratore, puoi usare una classe base
con getter e setter da usare nel bootstrap, e poi decorarla con una che
legge anche da un file YAML, a sua volta decorata da un'altra che fa
l'override dei valori prendendoli da DB, a sua volta decorata da un'altra
che fa caching di tutto l'ambaradan su memcache per non dover fare il
parsing ad ogni connessione.

Avresti

interface ConfigurationManager {
public function set($k, $v);
public function get($k);
}

class BasicConfig implements ConfigurationManager {
protected $config = array();
public function set($k, $v) { $this->config[$k] = $v; }
public function get($k) { return (@$this->config[$k] ?: null); }
}

class YAMLConfig implements ConfigurationManager {
protected $wrapped, $yamlFile, $parsed = false;
public function __construct($yamlFile, $wrapped) {
$this->wrapped = $wrapped;
$this->yamlFile = $yamlFile;
}
public function get($k) {
if (!$this->parsed) { $this->parseYaml(); }
$this->wrapped->get($k);
}
public function set($k, $v) {
if (!$this->parsed) { $this->parseYaml(); }
$this->wrapped->set($k, $v);
}
public function parseYaml($yamlFile) { ...; $this->parsed = true; }
}

class DBConfig implements ConfigurationManager {
protected $pdo, $wrapped, $parsed = false, $tableName;
public function __construct($pdo, $tableName, $wrapped) {
$this->wrapped = $wrapped;
$this->pdo = $pdo;
$this->tableName = $tableName;
}
public function get($k) {
if (!$this->parsed) { $this->parseDb(); }
$this->wrapped->get($k); }
}
public function set($k, $v) {
if (!$this->parsed) { $this->parseDb(); }
$this->wrapped->set($k, $v); }
}
public function parseDb() { ... }
}

class MemcachedConfig implements ConfigurationManager {
protected $memcache, $ttl, $wrapped;
public function __construct($memcache, $ttl, $wrapped) {
$this->wrapped = $wrapped;
$this->memcache = $memcache;
$this->ttl = $ttl;
}
public function get($k) {
if (time() < $ttl) {
return $this->getFromMemcache($k);
} else {
return $this->wrapped->get($k);
}
}
public function set($k, $v) {
$this->ttl = 0;
$this->wrapped->set($k, $v);
$this->saveAllToMemcache();
}
public function getFromMemcache($k) { ... }
public function saveAllToMemcache() { ... }
}

E, finalmente, nel bootstrap:

$config =
new MemcachedConfig(
new Memcached('blablabla'),
5*60,
new DbConfig(
new PDO('sqlite:/tmp/config.db'),
'configuration',
new YamlConfig(
'/etc/myapp.config.yaml',
new Config()
)
)
)
;

Vuoi testare senza memcache? Basta commentare le righe 2, 3, 4 a la
penultima (o scrivere il codice senza Piramidi di Paura e commentare solo
una riga).
Vuoi togliere il DB? Commenti la riga che decora con DbConfig.
Ecc. ecc.

Per questo ti dicevo che trovo il tuo controllo abbastanza inutile. Una
classe deve fare il minimo indispensabile.

Vuoi aggiungere il controllo? Fai un decoratore che, al set(), verifica
prima con un get() se il valore c'è già ed eventualmente lancia
un'eccezione.

Bye.

PS.: Ecco, oggi mi stavo decidento a scrivere un articolo sul blog e me
l'hai fatto scrivere qui. :P

alex

unread,
Apr 26, 2015, 2:17:39 AM4/26/15
to
Il 25/04/2015 17:31, Alessandro Pellizzari ha scritto:
> Vuoi aggiungere il controllo? Fai un decoratore che, al set(), verifica
> prima con un get() se il valore c'è già ed eventualmente lancia
> un'eccezione.

qualcosa tipo questa?

$value=123;
$config->set(new UnivocalValueChecker($config, $value));

Alessandro Pellizzari

unread,
Apr 29, 2015, 4:39:48 PM4/29/15
to
No, tipo questa:

class Config
{
public $values = array();
public function set($v) { $this->values[] = $v; }
}

class UnivocalConfig
{
protected $wrapped;
public function __construct($wrapped) {
$this->wrapped = $wrapped;
}
public function set($v) {
foreach ($this->wrapped->values as $value) {
if ($value == $v) {
throw new Exception('Cannot have duplicates');
}
}
$this->wrapped->set($v);
}
}

$config = new UnivocalConfig(new Config());

$config->set('pippo');
$config->set('pippo'); // -> Exception


Bye.

fma...@gmail.com

unread,
Apr 29, 2015, 5:03:52 PM4/29/15
to
On Saturday, April 25, 2015 at 5:31:24 PM UTC+2, Alessandro Pellizzari wrote:
> <snip>
> PS.: Ecco, oggi mi stavo decidento a scrivere un articolo sul blog e me
> l'hai fatto scrivere qui. :P

+10 solo perché sei riuscito (IMHO) a spiegare il tuo punto con il solo codice.
Non che personalmente farei tutto quest'uso di decorators, ma quando una
cosa è ben fatta fa piacere agli occhi leggerla.

Ciao!

Alessandro Pellizzari

unread,
Apr 29, 2015, 5:29:56 PM4/29/15
to
Il Wed, 29 Apr 2015 14:03:51 -0700, fmassei ha scritto:

> Non che personalmente farei tutto quest'uso di decorators

Ma nemmeno io. :D

Al massimo finora mi è capitato di usare uno o due decoratori.
L'esempio era un po' estremizzato per far capire cosa ci si poteva fare.

Bye.

alex

unread,
Apr 30, 2015, 2:53:20 PM4/30/15
to
Il 29/04/2015 22:39, Alessandro Pellizzari ha scritto:
> $config = new UnivocalConfig(new Config());
>
> $config->set('pippo');
> $config->set('pippo'); // -> Exception

grazie
0 new messages