2010-02-06 9 views
47

Ho questo codice. È possibile che un costruttore di oggetti User fallisca in qualche modo in modo che a $this->LoggedUser venga assegnato un valore NULL e l'oggetto venga liberato dopo il ritorni del costruttore?Costruttore PHP per restituire un valore NULL

$this->LoggedUser = NULL; 
if ($_SESSION['verbiste_user'] != false) 
    $this->LoggedUser = new User($_SESSION['verbiste_user']);  
+7

Grande prima domanda a proposito. –

+0

Ho visto un certo CMS popolare che restituisce FALSE in un costruttore. Cosa succede con quello?!?! – loungerdork

+1

Ho pensato di entrare qui per motivi di documentazione. Poiché la data è così indietro, è possibile che il CMS che stai vedendo sia stato creato per PHP4. PHP4 permetteva un sacco di cose cattive, non ultima delle quali permetteva all'utente di sovrascrivere $ nel costruttore chiamato (ad esempio $ this = false). – techdude

risposta

62

Supponendo che si sta utilizzando PHP 5, è possibile generare un'eccezione nel costruttore:

class NotFoundException extends Exception {} 

class User { 
    public function __construct($id) { 
     if (!$this->loadById($id)) { 
      throw new NotFoundException(); 
     } 
    } 
} 

$this->LoggedUser = NULL; 
if ($_SESSION['verbiste_user'] != false) { 
    try { 
     $this->LoggedUser = new User($_SESSION['verbiste_user']); 
    } catch (NotFoundException $e) {} 
} 

Per chiarezza, si potrebbe avvolgere questo in un statica metodo factory:

class User { 
    public static function load($id) { 
     try { 
      return new User($id); 
     } catch (NotFoundException $unfe) { 
      return null; 
     } 
    } 
    // class body here... 
} 

$this->LoggedUser = NULL; 
if ($_SESSION['verbiste_user'] != false) 
    $this->LoggedUser = User::load($_SESSION['verbiste_user']); 

per inciso, alcune versioni di PHP 4 ha permesso di impostare $ questo per NUL L all'interno del costruttore, ma non credo sia mai stato ufficialmente sanzionato e la "feature" è stata rimossa.

+4

+1 IMO, questo è il modo OO corretto per indicare il fallimento nella creazione di un oggetto. –

+1

Dipende dalla natura dell'errore. Se era un'eccezione, sì. Se un parametro per il costruttore non soddisfa un criterio, nella mia mente no. –

+5

Pekka, non sono sicuro che tipo di "parametri non validi" non costituiscano un'eccezione? Se non riesci a creare un oggetto valido con un certo insieme di parametri sicuramente questo è eccezionale e dovresti generare un'eccezione? Puoi fare un esempio per chiarire la distinzione a cui stai pensando? (Vedo che fai nella risposta qui sotto, sarebbe utile qui, ma non posso modificare il tuo commento!) –

11

per quanto ne so questo non può essere fatto, new sarà sempre restituire un'istanza dell'oggetto.

Cosa faccio di solito per ovviare a questo è:

  • L'aggiunta di un flag booleano ->valid all'oggetto che determina se un oggetto è stato caricato correttamente o meno. Il costruttore sarà quindi impostare il flag

  • Creazione di una funzione wrapper che esegue il comando new, restituisce il nuovo oggetto in caso di successo, o in caso di fallimento distrugge e restituisce false

-

function get_car($model) 
     { 
     $car = new Car($model); 
     if ($car->valid === true) return $car; else return false; 
    } 

Sarei interessato a conoscere approcci alternativi, ma non ne conosco nessuno.

+0

Grazie per aver chiarito. Quindi, in pratica, ho potuto inserire il nuovo comando nel tentativo ...catturare e quindi generare un'eccezione in un costruttore? – Tibor

+1

Buona domanda! Penso che * puoi *, ma in realtà non mi sembra giusto. Se creo un'auto oggetto con il modello "Ford", potrebbe semplicemente essere che nessuna macchina di quel modello si trova nel database. Questo non è esattamente ciò per cui * le eccezioni * sono state progettate. È più di una condizione prevista. Sarei interessato a vedere quali altre risposte emergono, ciò che viene visto come il modo "giusto" per gestirlo. –

+0

questo sta facendo la cosa in modo sporco, controlla la risposta di @jaz303 – minhajul

3

Quando un costruttore non riesce per qualche motivo sconosciuto, non restituirà un valore NULL o FALSE ma genera un'eccezione. Come con tutto con PHP5. Se non gestisci l'eccezione, lo script smetterà di essere eseguito con un errore Eccezione non rilevata.

+1

Quando un costruttore lancia un'eccezione? Quando restituisce falso? O vuoi dire, un costruttore dovrebbe lanciare un'eccezione se una determinata condizione non può essere soddisfatta? –

+1

Il costruttore deve lanciare l'eccezione. – Tom

5

Consideralo in questo modo. Quando si utilizza new, si ottiene un nuovo oggetto. Periodo. Quello che stai facendo è che hai una funzione che cerca un utente esistente e la restituisce quando viene trovata. La cosa migliore da esprimere è probabilmente una funzione di classe statica come User :: findUser(). Questo è anche estendibile a quando si stanno derivando le classi da una classe base.

+0

Sembra il più logico, sì. Ho appena iniziato la programmazione OO in PHP, quindi non sono completamente sicuro su come gestire le cose in un modo "corretto". – Tibor

3

forse qualcosa di simile:

class CantCreateException extends Exception{ 
} 

class SomeClass { 
    public function __construct() { 
     if (something_bad_happens) { 
      throw (new CantCreateException()); 
     } 
    } 
} 

try{ 
    $obj = new SomeClass(); 
} 
catch(CantCreateException $e){ 
    $obj = null; 
} 
if($obj===null) echo "couldn't create object"; 
//jaz303 stole my idea an wrap it into a static method 
4

Una fabbrica potrebbe essere utile qui:

class UserFactory 
{ 
    static public function create($id) 
    { 
     return (
      filter_var( 
       $id, 
       FILTER_VALIDATE_INT, 
       [ 'options' => [ 'min_range' => 1, ] ] 
      ) 
       ? new User($id) 
       : null 
     ); 
    } 
}