2010-04-21 18 views
5

Piszę aplikację internetową (PHP) dla mojego przyjaciela i zdecydowałem się użyć mojego ograniczonego szkolenia OOP z Javy.Wyjątki PHP w klasach

Moje pytanie brzmi: jaki jest najlepszy sposób na odnotowanie w mojej klasie/aplikacji, że pewne krytyczne rzeczy zawiodły, nie powodując w rzeczywistości mojej strony.

Mój problem polega na tym, że mam obiekt "SummerCamper", który pobiera argument camper_id jako jego argument, aby załadować wszystkie niezbędne dane do obiektu z bazy danych. Powiedzmy, że ktoś określa identyfikator camper_id w ciągu zapytania, który nie istnieje, przekazuję go do mojego konstruktora obiektów i ładowanie się nie powiedzie. Obecnie nie widzę sposobu, aby po prostu zwrócić false z konstruktora.

Czytałem mógłbym to zrobić z wyjątkami, rzuca wyjątek, jeśli żadne zapisy znajdują się w bazie danych lub jeśli jakiś walidacji nie na wejściu camper_id z aplikacji itp

Jednak ja tak naprawdę nie znalazłem świetnego sposobu na ostrzeżenie mojego programu, że ładowanie obiektów nie powiodło się. Próbowałem zwrócić false z wewnątrz CATCH, ale obiekt nadal występuje na mojej stronie php. Rozumiem, że mogę umieścić zmienną $ is_valid = false, jeśli obciążenie się nie powiedzie, a następnie sprawdzić obiekt za pomocą metody get, ale myślę, że mogą istnieć lepsze sposoby.

Jaki jest najlepszy sposób na uzyskanie podstawowego zakończenia obiektu w przypadku awarii obciążenia? Czy powinienem załadować dane do obiektu spoza konstruktora? Czy jest jakiś wzór, który powinienem sprawdzić?

Każda pomoc zostanie doceniona.

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; 
     } 



    } 

Odpowiedz

11

Zawsze będzie zwracana void. Ta funkcja nie działa. Nie działa. Throwing an Exception w konstruktorze

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

by zakończyć wykonanie skryptu, chyba że można go złapać gdzieś

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

Można przenieść powyższy kod do static method z SummerCamper tworzyć instancje to zamiast używać słowa kluczowego new (który jest powszechny w Javie słyszałem)

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; 
    } 
} 

w ten sposób można zrobić

$camper = SummerCamper::create(1); 

i dostać FALSE w $camper gdy $camper_id nie istnieje. Od statics are considered harmful możesz chcieć użyć Factory.

Inną opcją byłoby całkowite odłączenie dostępu do bazy danych od SummerCamper. Zasadniczo, SummerCamper jest podmiotem, który powinien martwić się tylko o rzeczy związane z SummerCamper.Jeśli dasz mu wiedzę, jak się utrzymać, skutecznie tworzysz ActiveRecord lub RowDataGateway. Można iść z podejściem 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; 
    } 
} 

i podmiotu,

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

DataMapper jest nieco bardziej skomplikowana, ale to daje oddzielić kod, który jest bardziej elastyczny i utrzymaniu w końcu. Rozejrzyj się w SO, istnieje wiele pytań na te tematy.

1

Rzucanie wyjątków od konstruktora jest prawdopodobnie właściwym podejściem. Możesz złapać to w odpowiednim miejscu i podjąć niezbędne działania (np. Wyświetlić stronę błędu). Ponieważ nie pokazałeś żadnego kodu, nie jest jasne, gdzie przechwyciłeś wyjątek lub dlaczego to nie zadziałało.

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

Gordon, chcesz pójść za tym przykładem tworzyć i używać twojego SummerCamper (jest to kod klienta dla twojej klasy), i USUŃ try {} catch {} z twojego konstruktora SummerCamper. Tak, jak to teraz napisałeś, pochłaniasz wyjątek, zanim kod klienta go zobaczy. – grossvogel

+0

@grossvogel nie ma próby/catch w konstruktorze. Zakładam, że odnosisz się do funkcji statycznej. Tam jest celowo. O ile rozumiem PO, nie jest on tak bardzo zaniepokojony faktycznym wyjątkiem, jak tylko zwykłym brakiem instancji. Ponadto, jeśli blok try/catch znajduje się poza metodą statyczną, musiałby powtórzyć próbę/catch, ilekroć będzie potrzebował stworzyć SummerCamper. To nie DRY. – Gordon

4

Aby dodać do odpowiedziach innych, należy pamiętać, że można rzucać różne rodzaje wyjątków od jednej metody i obsługiwać je każdy inaczej:

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

Tak. Dobry pomysł. – Gordon