Visualizzazione dei risultati da 1 a 9 su 9
  1. #1

    Problema con Classi ed Exceptions...e si perde il Distructor

    ho creato una classe all'interno della quale vengono lanciate delle eccezioni sia nel costruttore, che nei metodi e nel distruttore. La sintetizzo qui:

    codice:
    class FileOperation
    {
    public function __construct($file, $mode)
    {
    switch($mode)
    {
    case self::FILE_READ_BINARY:
    if(!(is_readable($file))) throw new FileOperationException("Il file non esiste o non hai i permessi di lettura su di esso", self::FILE_CANNOT_READ);
    $this->readable = TRUE;
    break;
    		
    case self::FILE_WRITE_BINARY:
    case self::FILE_APPEND_BINARY:
    if(is_file($file) && (!(is_writable($file)))) throw new FileOperationException("Non hai i permessi di scrittura sul file", self::FILE_NOT_WRITABLE);	
    $this->writable = TRUE;
    break;
    	
    default:
    throw new FileOperationException("Operazione sul file non consentita", self::FILE_WRONG_MODE);
    break;
    }		
    			
    if(!($this->risorsa = @fopen($file, $mode))) throw new FileOperationException("Errore nell'apertura del file", self::FILE_CANNOT_OPEN);			
    $this->modo_apertura = $mode;
    			
    }
    	
    public function WriteLine($stringa)
    {
    
    if(!($this->writable)) throw new FileOperationException("Il file e' stato aperto in modalita' di lettura", self::FILE_NOT_WRITABLE);
    if(!($byte_scritti = fwrite($this->risorsa, $stringa))) throw new FileOperationException("Errore sconosciuto di scrittura", self::FILE_CANNOT_WRITE);
    return $byte_scritti;
    
    }
    	
    function __destruct()
    {	
    if(!(@fclose($this->risorsa))) throw new FileOperationException("Errore nella chiusura del file", self::FILE_CANNOT_CLOSE);
    }
    }
    e ora la sto testando con questo codice:

    codice:
    try
    {
    $fp = new FileOperation("pippo.txt", FileOperation::FILE_WRITE_BINARY);
    $fp->WriteLine("scrivo una riga");
    }	
    catch (FileOperationException $e)
    { echo $e->getMessage(); }
    e mi sa di aver fatto un gran casino perche' se una eccezione viene chiamata dal costructor, l'oggetto nn viene proprio creato e quindi non è un problema

    Quando l'eccezione viene chiamata dal metodo WriteLine il distruttore NON viene chiamato

    Quando viene chiamata l'eccezione del distructor, addirittura, ho un fatal error di eccezione nn catturata

    dove ho sbagliato?
    Gabriele B. - http://9thcircle.it

  2. #2
    vedi se questo esempio puo' tornarti utile:

    codice:
    class Test {
    	private $__phrase;
    	final function __construct($__phrase = 'none', $forceException = false) {
    		$this->__phrase = $__phrase;
    		if($forceException)
    			$this->throwError();
    	}
    	final public function throwError() {
    		throw new Exception('
    This is an exception ['.$this.'] .');
    	}
    	final function __destruct() {
    		echo '<hr />'.$this->__phrase;
    	}
    }
    
    // forzare l' eccezione col metodo [ $t prima del try, esiste ]
    $t = new Test('destructor will be called ?');
    try {
    	$t->throwError();
    }
    catch(Exception $e) {
    	echo $e->getMessage();
    }
    if($t)
    	unset($t);
    echo '
    ----------------------------------';
    
    
    // forzare l' eccezione nel costruttore
    // [ $z nel try che non viene eseguito causa eccezione, $z non esiste ]
    try {
    	$z = new Test('destructor will be called in constructor ?', true);
    }
    catch(Exception $e) {
    	echo $e->getMessage();
    }


    Comunque effettivamente c'e' una "stranezza" ... concettualmente e' giusto che nel try, con l' oggetto creato dentro questo, ovvero $z, il distruttore non venga preso affatto in considerazione, visto che $z in teoria non esiste perche' il try non passa causa throw di Exception, pero' e' anche vero che tecnicamente $z esiste, poiche' l' exception scrive anche l' Object id ... e l' object id se presente, significa che esiste un object altrimenti darebbe un notice o un null ...

    tutto questo forse e' comunque sensato o forzatamente fatto cosi' poiche' se fallisce la costruzione di un oggetto, visto che esiste un' eccezione, questo non deve essere usato, quindi nemmeno il suo distruttore.

    [editato]
    probabilmente l' object esiste localmente dentro la chiamata alla classe , quindi viene eliminato dalla garbage collection appena viene richiamato il catch fuori dal contesto locale, ergo non esiste piu' ... ma e' esistito

    Puoi forzare il distruttore dentro il metodo di eccezione errore, cercando sulla GLOBALS ... pero' imho leggermente azzardato ...


    codice:
    class Test {
    	private $__phrase;
    	final function __construct($__phrase = 'none', $forceException = false) {
    		$this->__phrase = $__phrase;
    		if($forceException)
    			$this->throwError();
    	}
    	final public function throwError() {
    		$found = false;
    		foreach($GLOBALS as $key => &$value)
    			if($value instanceof Test)
    				if(!$found)
    					$found = true;
    		if(!$found)
    			$this->__destruct();
    		throw new Exception('
    This is an exception ['.$this.'] .');
    	}
    	final function __destruct() {
    		echo '<hr />'.$this->__phrase;
    	}
    }
    
    
    // forzare l' eccezione col metodo [ $t prima del try, esiste ]
    $t = new Test('destructor will be called ?');
    try {
    	$t->throwError();
    }
    catch(Exception $e) {
    	echo $e->getMessage();
    }
    if($t)
    	unset($t);
    echo '
    ----------------------------------';
    
    
    // forzare l' eccezione nel costruttore
    // [ $z nel try che non viene eseguito causa eccezione, $z non esiste ]
    try {
    	$z = new Test('destructor will be called in constructor ?', true);
    }
    catch(Exception $e) {
    	echo $e->getMessage();
    }
    Formaldehyde a new Ajax PHP Zero Config Error Debugger

    WebReflection @WebReflection

  3. #3
    ciao e grazie per il codice, mi ha fatto capire un po' di cose in piu'...

    con delle semplici modifiche al codice adesso le eccezioni nei metodi vengono chiamate correttamente, nel senso che il distruttore viene eseguito come dovrebbe al termine delle quali

    credo di aver capito, invece, perche' il distruttore non è in grado di chiamare l'eccezione: è un semplice, quanto ostico, problema di scope dell'oggetto

    l'oggetto infatti, locale al blocco try, viene distrutto all'uscita da questo e quindi "fuori" dalla condizione try-catch che dovrebbe catturarne l'eccezione

    Potrei nidificare il blocco try catch in un altro, ma non credo che ne valga la pena in termini di legibbilità ed efficenza del codice, piuttosto "sacrifico" l'eccezione nel distruttore (in fondo si tratta di un evento/errore praticamente inverificabile)

    a meno che non ci sia un'altra soluzione...
    Gabriele B. - http://9thcircle.it

  4. #4
    l' altra soluzione semplicissima e' di non mettere throw sul costruttore ... tanto piu' quando il distruttore ti serve cosi' tanto ...

    a quel punto il try lo fai su un metodo e il costruttore lo usi, o anche no, solo per inizializzare la variabile.

    Cioe', il problema e' molto semplice, e' come vuoi affrontarlo che e' complicato
    Formaldehyde a new Ajax PHP Zero Config Error Debugger

    WebReflection @WebReflection

  5. #5
    si, mi sa che e' la cosa piu' logica da fare...è che mi piaceva l'idea che, a conti fatti, l'oggetto nn viene nemmeno creato, se per un motivo o per un altro nn è possibile effettuare operazioni su quel file

    anzi, a lume di naso sarebbe ancora meglio se concentrassi tutte le eccezioni proprio nel costruttore e basta...

    cmq alla fine lo lascio cosi' il codice, in fondo nn mi serve era solo per imparare ad usare classi ed eccezioni

    una digressione: posso abbandonare del tutto (o quasi) gli error handler? questo nuovo metodo e le mie rimembranze di java mi portano a pensare che sia DECISAMENTE meglio...
    Gabriele B. - http://9thcircle.it

  6. #6
    allora, il concetto e' semplice ...

    ti serve non creare il metodo ?

    metti throw sul costruttore ma ovviamente devi verificare cosa ti e' possibile fare prima di farlo e di inviare eventualmente l' Exception ... non puoi puntare tutto sul distruttore ... il distruttore serve solo se la variabile / oggetto esiste

    per esempio prima di fare operazioni di scrittura verifichi che il file sia scrivibile e/o creabile e in caso contrario invii l' eccezione, no che intanto lavori sul file poi a meta' ti "ricordi" che se non puoi andare avanti devi cancellare tutto quello che hai fatto, non stai usando transazioni in database, stai lavorando su variabili e files


    Poi, sull' error_handler non saprei che dire , in realta' non e' detto che uno esclude l' altro , puoi usarli insieme, usare solo le eccezioni e lasciare comunque l' error_handler libero di notificare o warningare durante lo sviluppo ... poi puoi eliminarlo e basare tutto sulle eccezioni ma di fatto non sono la stessa cosa, molto simili per certi versi, ma non identici
    Formaldehyde a new Ajax PHP Zero Config Error Debugger

    WebReflection @WebReflection

  7. #7
    beh grosso modo e' gia' cosi'...tutti i controlli li fa il costruttore

    i metodi lanciano delle eccezioni solo in ritorno ad errori delle funzioni base ivi contenute, oppure in caso di operazioni non lecite

    la WriteLine, ad esempio, controllo lo stato della variabile $writable, prima di eseguire la scrittura. Magari posso fargli tornare FALSE in caso la scrittura nn sia possibile senza scomodare una eccezione, ma credo sia concettualmente piu' giusto che quando la prima operazione su di un file fallisca questo venga chiuso ed ulteriori operazioni nn vengono eseguite

    quindi nn mi sembra di effettuare controlli a meta' strada

    nn vorrei sembrare pignolo, ma come ti dicevo sto facendo questo script come un "tutorial", quindi cerco di essere il piu' preciso possibile a livello di concetto

    poi il real world programming verra' dopo
    Gabriele B. - http://9thcircle.it

  8. #8
    Originariamente inviato da TheClue/Nash
    quindi nn mi sembra di effettuare controlli a meta' strada
    basare uno script su un distruttore che puo' non essere richiamato a causa della costruzione dell' oggetto in un try e' gia' un "controllo" a meta' strada ...


    il real world programming non puo' esistere se non si e' in grado di capire cosa si sta' facendo .. purtroppo il php permette ad alcuni di praticare senza sapere, ma poi fanno porcate allucinanti ... cose che capitano anche a me, per carita', pero' con minore frequenza e solitamente facilmente risolvibili

    Formaldehyde a new Ajax PHP Zero Config Error Debugger

    WebReflection @WebReflection

  9. #9
    ma il distruttore nn serve, se l'oggetto nn viene creato

    il costruttore apre il file
    il distruttore lo chiude

    se il costruttore nn apre il file perchè torna una eccezione, il distruttore nn serve

    mi serviva che venisse chiamato dopo le eccezioni dei metodi, a file quindi gia' aperto. ma studiando il codice che mi hai postato ho capito l'errore e ho risolto
    Gabriele B. - http://9thcircle.it

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.