2010-04-21 16 views
5

Sto scrivendo un'applicazione Web (PHP) per il mio amico e ho deciso di utilizzare il mio addestramento OOP limitato da Java.PHP Eccezioni nelle classi

La mia domanda è qual è il modo migliore per notare nella mia classe/applicazione che determinate cose critiche hanno fallito senza in realtà infrangere la mia pagina.

Il mio problema è che ho un oggetto "SummerCamper" che accetta un camper_id come argomento per caricare tutti i dati necessari nell'oggetto dal database. Supponiamo che qualcuno specifichi un camper_id nella stringa di query che non esiste, lo passo al costruttore di oggetti e il caricamento non riesce. Attualmente non vedo un modo per me di restituire false dal costruttore.

Ho letto avrei potuto fare questo con eccezioni, un'eccezione se nessun record sono presenti nella banca dati o se un qualche tipo di convalida non riesce su input del camper_id dall'applicazione ecc

Tuttavia, non ho davvero trovato un ottimo modo per avvisare il mio programma che il carico dell'oggetto è fallito. Ho provato a restituire false dall'interno del CATCH ma l'oggetto persiste ancora nella mia pagina php. Capisco che potrei inserire una variabile $ is_valid = false se il caricamento fallisce e quindi controllare l'oggetto usando un metodo get ma penso che ci possano essere modi migliori.

Qual è il modo migliore per raggiungere la chiusura essenziale di un oggetto in caso di guasto di un carico? Dovrei caricare i dati nell'oggetto dall'esterno del costruttore? C'è una sorta di modello di progettazione che dovrei esaminare?

Qualsiasi aiuto sarebbe apprezzato.

function __construct($camper_id){ 
     try{ 
      $query = "SELECT * FROM campers WHERE camper_id = $camper_id"; 
      $getResults = mysql_query($query); 

      $records = mysql_num_rows($getResults); 

      if ($records != 1) { 
       throw new Exception('Camper ID not Found.'); 
      } 

      while($row = mysql_fetch_array($getResults)) 
      { 
       $this->camper_id = $row['camper_id']; 
       $this->first_name = $row['first_name']; 
       $this->last_name = $row['last_name']; 
       $this->grade = $row['grade']; 
       $this->camper_age = $row['camper_age']; 
       $this->camper_gender = $row['gender']; 
       $this->return_camper = $row['return_camper']; 
      } 
     } 
     catch(Exception $e){ 
      return false; 
     } 



    } 

risposta

11

A constructor in PHP restituirà sempre void. Questo

public function __construct() 
{ 
    return FALSE; 
} 

non funziona. Throwing an Exception nel costruttore

public function __construct($camperId) 
{ 
    if($camperId === 1) { 
     throw new Exception('ID 1 is not in database'); 
    } 
} 

sarebbe terminare l'esecuzione di script a meno che non si cattura da qualche parte

try { 
    $camper = new SummerCamper(1); 
} catch(Exception $e) { 
    $camper = FALSE; 
} 

Si potrebbe spostare il codice sopra in un static method di SummerCamper per creare istanze di esso invece di utilizzare la parola chiave new (che è comune in Java ho sentito)

class SummerCamper 
{ 
    protected function __construct($camperId) 
    { 
     if($camperId === 1) { 
      throw new Exception('ID 1 is not in database'); 
     } 
    } 
    public static function create($camperId) 
    { 
     $camper = FALSE; 
     try { 
      $camper = new self($camperId); 
     } catch(Exception $e) { 
      // uncomment if you want PHP to raise a Notice about it 
      // trigger_error($e->getMessage(), E_USER_NOTICE); 
     } 
     return $camper; 
    } 
} 

in questo modo si potrebbe fare

$camper = SummerCamper::create(1); 

e ottenere FALSE nel $camper quando il $camper_id non esiste. Dal statics are considered harmful, potresti invece voler utilizzare una Fabbrica.

Un'altra opzione sarebbe quella di disaccoppiare l'accesso al database dal SummerCamper del tutto. Fondamentalmente, SummerCamper è un'entità che dovrebbe preoccuparsi solo delle cose SummerCamper.Se gli dai la conoscenza di come persistere, stai creando in modo efficace un ActiveRecord o RowDataGateway. Si potrebbe andare con un approccio DataMapper:

class SummerCamperMapper 
{ 
    public function findById($id) 
    { 
     $camper = FALSE; 
     $data = $this->dbAdapter->query('SELECT id, name FROM campers where ?', $id); 
     if($data) { 
      $camper = new SummerCamper($data); 
     } 
     return $camper; 
    } 
} 

e la tua Entità

class SummerCamper 
{ 
    protected $id; 
    public function __construct(array $data) 
    { 
     $this->id = data['id']; 
     // other assignments 
    } 
} 

DataMapper è un po 'più complicato, ma ti dà disaccoppiato codice che è più gestibile e flessibile alla fine. Dai un'occhiata in giro, c'è una serie di domande su questi argomenti.

1

Lanciare un'eccezione dal costruttore è probabilmente l'approccio giusto. Puoi prenderlo in un posto appropriato e prendere le misure necessarie (ad es. Visualizzare una pagina di errore). Dato che non hai mostrato alcun codice, non è chiaro dove stavi catturando la tua eccezione o perché non sembrava funzionare.

1
try { 
    $camper = new SummerCamper($id); 
    $camper->display(); 
} catch (NonexistentCamper $ex) { 
    handleFailure($ex); 
} 
+0

Gordon, si vuole seguire questo esempio per creare e utilizzare il tuo SummerCamper (questo è il codice client per la tua classe) e RIMUOVERE il try {} catch {} dal tuo costruttore SummerCamper. Il modo in cui lo hai scritto ora, stai ingoiando l'eccezione prima che il codice client possa vederlo. – grossvogel

+0

@grossvogel non c'è try/catch nel costruttore. Presumo che tu stia facendo riferimento alla funzione statica. Eccolo di proposito. Per quanto ho capito dell'OP, non è tanto preoccupato dell'effettiva eccezione di quanto non stia semplicemente ottenendo un'istanza. Inoltre, se il blocco try/catch è fuori dal metodo statico, dovrebbe ripetere il try/catch ogni volta che ha bisogno di creare un SummerCamper. Non è ASCIUTTO. – Gordon

4

Per aggiungere alle risposte degli altri, tenere a mente che si può buttare diversi tipi di eccezioni da un unico metodo e ogni maniglia in modo diverso:

try { 
    $camper = new SummerCamper($camper_id); 
} catch (NoRecordsException $e) { 
    // handle no records 
} catch (InvalidDataException $e) { 
    // handle invalid data 
} 
+2

Sì. Buon suggerimento – Gordon