Исключения PHP в классах - PullRequest
6 голосов
/ 21 апреля 2010

Я пишу веб-приложение (PHP) для моего друга и решил использовать мое ограниченное обучение ООП из Java.

Мой вопрос заключается в том, как лучше всего заметить в моем классе / приложении, что конкретные критические вещи потерпели неудачу, не сломав мою страницу.

Моя проблема в том, что у меня есть объект "SummerCamper", который принимает camper_id в качестве аргумента для загрузки всех необходимых данных в объект из базы данных. Скажем, кто-то указывает camper_id в несуществующей строке запроса, я передаю его конструктору объектов, и загрузка завершается неудачно. В настоящее время я не вижу способа вернуть false из конструктора.

Я прочитал, что мог бы сделать это с помощью Исключений, выдав исключение, если в базе данных не найдено записей или если какая-либо проверка не удалась при вводе camper_id из приложения и т.д.

Однако я не нашел хорошего способа предупредить мою программу о сбое загрузки объекта. Я попытался вернуть false из CATCH, но объект все еще сохраняется на моей странице php. Я понимаю, что мог бы поместить переменную $ is_valid = false, если загрузка не удалась, а затем проверить объект с помощью метода get, но я думаю, что могут быть и лучшие способы.

Каков наилучший способ достижения существенного завершения объекта в случае сбоя загрузки? Должен ли я загрузить данные в объект извне конструктора? Есть какой-то шаблон дизайна, который я должен изучить?

Любая помощь будет оценена.

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



    }

Ответы [ 4 ]

14 голосов
/ 21 апреля 2010

Конструктор в PHP всегда будет возвращать void. Это

public function __construct()
{
    return FALSE;
}

не будет работать. Создание исключения в конструкторе

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

прервет выполнение скрипта, если вы не поймаете его где-нибудь

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

Вы можете переместить приведенный выше код в статический метод SummerCamper, чтобы создать его экземпляры, вместо использования ключевого слова new (что часто встречается в Java, я слышал)

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

Таким образом, вы могли бы сделать

$camper = SummerCamper::create(1);

и получите FALSE в $camper, когда $camper_id не существует. Поскольку статика считается вредной , вы можете использовать вместо нее Фабрику.

Другой вариант - полностью отделить доступ к базе данных от SummerCamper. По сути, SummerCamper - это сущность, которая должна заботиться только о SummerCamper вещах. Если вы даете ему знания о том, как сохранить себя, вы фактически создаете ActiveRecord или RowDataGateway . Вы могли бы пойти с 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;
    }
}

и ваша сущность

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

DataMapper несколько сложнее, но он дает вам разъединенный код, который, в конце концов, более удобен в обслуживании и гибок. Посмотрите вокруг, есть ряд вопросов по этим темам.

5 голосов
/ 21 апреля 2010

Чтобы добавить ответы других, помните, что вы можете создавать различные типы исключений из одного метода и обрабатывать их по-разному:

try {
    $camper = new SummerCamper($camper_id);
} catch (NoRecordsException $e) {
    // handle no records
} catch (InvalidDataException $e) {
    // handle invalid data
}
1 голос
/ 21 апреля 2010
try {
    $camper = new SummerCamper($id);
    $camper->display();
} catch (NonexistentCamper $ex) {
    handleFailure($ex);
}
1 голос
/ 21 апреля 2010

Создание исключения из конструктора, вероятно, правильный подход.Вы можете поймать это в соответствующем месте и предпринять необходимые действия (например, отобразить страницу с ошибкой).Поскольку вы не показывали никакого кода, неясно, где вы ловили свое исключение или почему это не сработало.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...