Пытаясь перейти от глобального процедурного кодирования к более ООП-ориентированному стилю, я реорганизую веб-сайт для журнала.
Одно из условий проверки на сервере — передан ли идентификатор статьи или комбинация года / выпуска. В первом случае пользователю должна быть предоставлена конкретная статья, во втором — оглавление и изображение. обложка для выбранного номера. Мне также нужно получить год и выпустить для отображения во втором случае.
Моим первым инстинктом было поместить всю логику в конструктор:
class Magazine {
public $year;
public $issue;
public function __construct($year, $issue, $articleId = 0) {
if($articleId > 0) {
// Get article from database
$this->year = // get year from search results;
$this->issue = // get number from search results;
} else {
// Get table of contents and cover image
}
}
}
// Create an instance either like this:
$magazine = new Magazine(1985, 3);
// Or like this:
$magazine = new Magazine(0, 0, 172);
Но потом я понял, что, вероятно, не стоит «перегружать» конструктор таким образом (чтобы компенсировать невозможность его перегрузить в обычном смысле?).
Итак, я создаю метод для извлечения статьи, например так:
class Magazine {
public $year;
public $issue;
private $articleId;
public function __construct($year, $issue, $articleId = 0) {
$this->year = $year;
$this->issue = $issue;
$this->articleId = $articleId;
}
public function getArticle() {
// Use $this->articleId to retrieve data from database
// Set $this->year and $this->issue to appropriate values
}
}
Или без конструктора:
class Magazine {
public $year;
public $issue;
public function getArticle($articleId) {
// Use $articleId to retrieve data from database
// Set $this->year and $this->issue to appropriate values
}
}
Нет, присвоение значений году и свойствам выпуска не является частью получения статьи. Поэтому я создаю другой метод для этого:
public function getYearAndIssue($articleId) {
// Use $articleId to retrieve data from database
}
Но теперь мне нужно подключиться к базе данных дважды. Нехорошо. Кажется, мне нужно собрать все данные, которые мне нужны при первом подключении к БД. И где мне это сделать? В конструкторе? Нет, это просто вернет меня на круги своя. Или минус один.
Так куда мне идти отсюда? Два метода, как getArticleAndEverythingElseINeedForThat() { // ... }
а также getCoverAndEverythingElseINeedForThat() { ... }
?
РЕДАКТИРОВАТЬ: Благодаря комментарию Даана я поэкспериментировал еще немного и придумал следующее:
class Magazine {
private $db;
public function __construct($db) {
$this->db = $db;
}
public function getArticle($articleId) {
$sql = "SELECT article FROM table WHERE id = :id";
$ph = array(':id' => $articleId);
$ps = $this->db -> prepare($sql);
$ps -> execute($ph);
// Do some more stuff
return $article;
}
public function getYearAndIssue($articleId) {
$sql = "SELECT year, issue FROM table WHERE id = :id";
$ph = array(':id' => $articleId);
...
return array($year, $issue);
}
}
class Database {
public static function getConnection() {
$db = new PDO(...);
$db->setAttribute(...);
...
return $db;
}
}
$db = Database::getConnetion();
$magazine = new Magazine($db);
$article = $magazine->getArticle(59);
list($year, $issue) = $magazine->getYearAndIssue(59);
Новые вопросы:
Кажется ли я близко, чтобы понять инъекции?
В некоторых описаниях я видел, что объект PDO создается как частная переменная в конструкторе и передается в качестве аргумента вспомогательным функциям, то есть, как если бы я написал свой код следующим образом:
class Magazine {
private $db;
public function __construct($db) {
$this->db = $db;
}
public function getArticle($db, $articleId) {
// ...
}
}
$db = Database::getConnetion();
$magazine = new Magazine($db);
$article = $magazine->getArticle($db, 59);
Должен ли я сделать это тоже? Если так, то почему?
Даже если я использую одно и то же соединение с БД дважды (или чаще в реальном сценарии), мне все равно придется получать данные из БД несколько раз. Разве не было бы лучше / быстрее получить все, что мне нужно, от БД сразу (если это было бы возможно, не испортив логику снова / дальше)? Как это:
$sql = "SELECT article, year, issue FROM table WHERE id = :id";
Задача ещё не решена.
Других решений пока нет …