PHP Class / OOP: когда «ссылаться» на класс внутри класса или расширять класс? - PullRequest
2 голосов
/ 07 января 2012

Когда идеально:

class USER {
    // stuff about user
}

class PROFILE extends USER {
    // stuff about user's profile
}

, а когда идеально:

class USER {
    $id;
    $profile;

    function __construct($id) {
        $this->id = $id;
        $this->profile = new PROFILE($id);
        // set profile variables
    }
}

class PROFILE {
    $id;
    // other variables pertaining to profile

    function __construct($id) {
        $this->id = $id;
    }
}

Мне более комфортно со вторым примером?Есть ли какие-то конкретные предостережения, о которых я должен знать?

Должен ли я думать об одном как о не взаимно исключающих подмножествах, а о другом, как о детях?

Ответы [ 4 ]

2 голосов
/ 07 января 2012

Это классический вопрос инкапсуляции и наследования .

Использование инкапсуляции:

  • Когдавы хотите предоставить некоторые функциональности базового класса, но хотите скрыть некоторые из них.
  • Когда вы хотите расширить / изменить функциональность базового класса, но не хотитеон должен быть совместимым с типами.

Использовать наследование:

  • Когда вам нужно, чтобы производные классы были совместимы по типу с базовым классом,Другими словами, если клиентский код должен ссылаться на экземпляры Derived с Base ссылками.

В вашем примере для PROFILE не имеет смысла наследоваться от USER.Пользователь имеет профиль, но профиль не является пользователем.В этом примере имеет смысл, чтобы класс USER содержал поле PROFILE.

1 голос
/ 07 января 2012

Как правило, если вы не можете сказать, что PROFILE - это просто особый вид USER, и во всех случаях его можно трактовать как USER, вы не хотите использовать наследование для моделирования отношений,A USER может иметь a PROFILE, или PROFILE может быть , связанным с конкретным USER, но оба являются различными объектами - поэтому ни один не долженнаследовать от другого.

1 голос
/ 07 января 2012

Я бы сказал, что реальный способ сделать это был бы:

class User {

    private $id,
            $profile;

    public function __construct($id, Profile $profile) {
        $this->id = $id;
        $this->profile = $profile;
    }

}

class Profile { ... }

new User(42, new Profile(...));

Вы не хотите расширять класс, если нет четкой иерархии (Admin extends User).
Вытакже не следует связывать классы, как вы делали в конструкторе User, а использовать внедрение зависимостей, как показано выше.

0 голосов
/ 07 января 2012

Обычно родительские классы больше похожи на общие классы, которые вы собираетесь расширять и редко используете самостоятельно.Таким образом, наследование больше похоже на то, каким оно должно быть: вы расширяете универсальный класс.

Я не собираюсь снова обращаться к метафоре животного, но что-то вроде:

class USER {} // generic class

class ADMIN extends USER {} // specific class

class MOD extends USER {} // specific class

имеет логику, потому что мы расширяем универсальный класс USER, чтобы указать класс для каждого типа пользователя.

Для всего, что не является иерархическим, я бы использовал инкапсуляцию.

...