Я - относительно новое ООП использования в PHP. Этому помогают очень в организации и обслуживании моего кода, но я хотел бы поправиться при разработке моих классов и использовании ООП так эффективно, как я могу. Я считал Банду Четырех книг Шаблонов разработки, но все еще нуждаюсь в некоторой помощи. После создания нескольких небольших приложений вот одна вещь, через которую я продолжаю бежать.
Скажем, я создаю приложение, которое отслеживает информацию о приеме для школы.
Путем я в настоящее время приближался бы, этому нужно было назвать класс student
, и методы в том классе для CRUD на записи отдельного студента. Кажется логичным, что у меня был бы метод конструктора для этого класса, который взял student_id
как аргумент, таким образом, я мог сослаться на него из объекта для всех тех различных операций CRUD.
Но затем, в то время как я продолжаю создавать приложение, я натыкаюсь на ситуации, где мне нужно к выполнению запросов, которое возвращает несколько студентов. Например, что-то как, get_all_students_from_grade($grade)
, get_dropdown_of_all_students()
, и т.д. Эти методы не относятся всего к одному студенту, таким образом, это кажется нечетным, что у меня были бы они как методы в моем student
класс, так как я инстанцировал объекта с одним student_id
в памяти. Очевидно, я могу заставить его проложить себе путь, но кажется, что я 'делаю его неправильно'. Что лучший способ состоит в том, чтобы приблизиться к этому?
Отделите класс student
(который является классом домена) от операций над ним (бизнес-логика или доступ к данным, в зависимости от случая), например:
student
- объект домена содержит только данныеstudent_service
или student_dao
(Объект доступа к данным) - выполняет операцииИногда это считается нарушением инкапсуляции, но это общепринятая лучшая практика.
Вот дополнительная информация по этому вопросу. Он предоставляет больше недостатков с точки зрения ООП, чем нарушение инкапсуляции. Таким образом, даже если это кажется общепринятой практикой, это не совсем ООП
.Разбейте его на два класса:
Ваш ученический класс ничего не знает о том, как он хранится по отношению.
$students = student_repository.get_all_students_from_grade($grade)
Я не притворяюсь, что знаю "лучший" способ, но это может помочь по-другому подойти к проблеме. Вместо того, чтобы делать один класс для представления отдельного учащегося, можно сделать так, чтобы он представлял собой интерфейс данных между вашим приложением и базой данных.
Этот класс знал бы, как получить связку (возможно, одну) строк ученика из db, кэшировать их в локальном массиве, позволить приложению просматривать кэшированные записи, разрешить изменения в записях в кэше, а когда это будет сделано, записать кэшированные изменения обратно в db (сгенерировав SQL для учёта изменений).
Таким образом, вы избегаете запуска одного SQL-состояния для каждого изменения (вы все еще работаете с набором строк вместо него) и в то же время предлагаете доступ к отдельным объектам (поддерживая индекс к текущему местоположению в кэше, и позволяете этому "указателю" быть расширенным приложением, как он вызывает методы вашего класса)
.Всегда есть отправная точка. В вашем случае это было бы то, откуда вы забираете учеников (т.е. из школы, класса и т.д.).
$class = new Model_Class;
$students = $class->students;
foreach($students as $student)
{
print $student->name. ' is in class '. $class->name;
}
Вы можете пойти по заводскому методу и попросить фабрику решить, каким должен быть ID нового ученика.
Конечно, эта фабрика должна будет прочитать базу данных, чтобы увидеть, с чего начать индекс (исходя из того, сколько учеников в вашей базе данных), и вы должны будете решить, что делать с удаленными учениками (если это возможно).
Что касается методов, которые вы описали, то я не вижу причин, по которым вы должны включать их в свой класс. Вы могли бы, но это должен быть статический метод, а не метод-член
. Как сказал Нил в своем комментарии (не уверен, почему мы не ответили на этот вопрос), наверное, вам также следует пройти курс
и занятия в школе
. Вы можете иметь специфические для школы методы (получение всех учеников в данном классе, с заданным количеством пропущенных дней и т.д.) в School
и специфические для данного курса методы (все ученики в курсе с определенным классом и т.д.) в классе Course
.
Вы правы, думая, что в стандартном CRUD вы не хотите давать классу, представляющему отдельное лицо (т.е. Student
class), ответственность за загрузку кратных единиц себя самого. С другой стороны С другой стороны , если бы вы выбрали более ActiveRecord стиль загрузки данных (который использует Ruby on Rails), то вы на самом деле сделали бы все методы загрузки Student
статическими на самом классе Student
. Это зависит только от того, как вы хотите его стилизовать, что отчасти зависит от того, насколько сложной будет становиться ваша модель данных.
Я столкнулся с той же проблемой. Полагаю, вы используете MySQL? это одна из распространенных проблем проектирования ООП, потому что SQL имеет тенденцию все сглаживать.
Я решил эту проблему, выполнив следующие действия
1.) Создайте класс, имеющий три формы создания экземпляров,
одну, где она новая
$myStudent = new $Student();
, другую, в которой вы знаете идентификатор, но нуждаетесь в данных идентификаторов
$myStudent = new $Student($student_id);
и другой, где у вас уже есть данные в ассоциативном массиве
$data = array('id'=13,'name' => 'studentname', 'major' => 'compsci');
$myStudent = new $Student($data['id'], $data);
. Это позволяет вам создать фабричный класс, который может запускать запрос из mysql, получать ассоциативный массив данных, а затем создавать экземпляры student из данных этого массива без попадание в базу данных для каждого экземпляра студента.
вот конструктор для такого класса:
public function __construct($id=FALSE, $data=FALSE)
{
if(!$id) $this->is_new = true;
else if($id && !$data) $this->get_data_from_db($id);
else if($id && $data) $this->set_data($data);
}