Доктрина 2. Каков рекомендуемый способ доступа к свойствам?

Я помню, как читал, что в моделях Doctrine 2 я не должен устанавливать общедоступные свойства/поля. Как тогда вы выставляете эти поля? В песочнице использовались методы get*() и set*(). Это лучшая идея? Это очень громоздко. Использование магических методов __get() __set() сделает вещи похожими на настройку полей общедоступными?

Какова ваша рекомендация?


person Jiew Meng    schedule 16.12.2010    source источник
comment
Есть много других веских причин, по которым вы также не должны делать свои свойства класса общедоступными! Наиболее очевидным является то, что если они общедоступны, я могу установить их значения абсолютно любыми, какими захочу, независимо от того, какими они должны быть. Например, если предполагается, что свойство $foo является объектом класса Bar, но является общедоступным, то как запретить кому-то другому устанавливать для него что-либо, кроме экземпляра класса Bar? Я мог бы сделать его экземпляром класса Quux, целым числом, функцией... Что касается __get и __set, магия делает код намного более трудным для понимания, и ее следует избегать.   -  person GordonM    schedule 01.07.2014


Ответы (6)


Вот почему вы не можете использовать общедоступные свойства: Как можно общедоступные поля «прерывают ленивую загрузку» в Doctrine 2?

Вы правы, что __get() и __set() могут облегчить доступ к полям protected/private.

Вот простой пример:

public function __get($name)
{
  if(property_exists($this, $name)){
    return $this->$name;
  }
}

Конечно, это дает доступ ко всем свойствам. Вы можете поместить это в класс, расширенный всеми вашими объектами, а затем определить неоцениваемые поля как private. Или вы можете использовать массив, чтобы определить, какие свойства должны быть доступны: $this->accessable = array('name', 'age')

Существует множество способов защитить все свойства и при этом иметь достаточно простой способ их получения/установки.

person Tim Lytle    schedule 16.12.2010
comment
Я бы не советовал использовать __get и __set в ваших сущностях только потому, что вам лень их писать самому. Есть случаи, когда может иметь смысл использовать магический метод, но это зависит от цели сущностей. Большинство IDE могут сгенерировать их для вас. - person Cobby; 10.02.2011
comment
@Cobby В официальной документации доктрины2 указано: ...We therefore urge you to map only private and protected properties on entities and use getter methods or magic __get() to access them. doctrine- project.org/docs/orm/2.0/en/reference/ - person Petr Peller; 20.05.2011
comment
@Cobby Вы когда-нибудь слышали о наследовании? Я до сих пор не вижу причины, почему лучше (автоматически или нет) написать сотни строк кода, чем около 20 в классе BaseEntity. - person Petr Peller; 22.05.2011
comment
Вам не нужно писать код, его генерируют IDE. В противном случае потребуется около 3 минут, чтобы напечатать его самостоятельно. - person Cobby; 23.05.2011
comment
@Tim Lytle, вместо использования $this-›accessable мы можем использовать текущие ClassMetadata::$fieldNames со списком полей нашего объекта - person Mikl; 30.05.2014
comment
Просто мысль... Технически вы могли бы использовать магический геттер и сеттер для вызова чего-то вроде $function = 'get' . ucfirst($name); $this->$function(); Я знаю, что это не поможет вам НЕ писать код... но нет никаких причин, по которым вы не могли бы проверить, работает ли функция не существовало, а затем вместо этого извлеките свойство. Это позволит вам перегружать эти геттеры и сеттеры, не делая прямого сопоставления там, где вам это нужно, и поддерживать красивый короткий синтаксис $object->property. - person General Redneck; 12.02.2018

Лично мне не нравится шаблонный код с тривиальной целью — он делает код уродливым и утомительным для чтения. Поэтому я настоятельно предпочитаю __get/__set. Тем не менее, у них есть несколько недостатков:

  • они значительно медленнее, чем обычные вызовы функций, хотя и не настолько, чтобы на практике это имело значение, поскольку база данных доступ на несколько порядков медленнее
  • __get/__set вызывается только тогда, когда поле не видно; если вы обращаетесь к свойствам в коде класса сущности, они не вызываются, и у прокси нет возможности загрузить себя. (Doctrine пытается избежать этого, мгновенно загружая прокси-сервер, как только вызывается один из его общедоступных методов, но есть некоторые исключения, такие как __construct или __wake, где это не имеет смысла, поэтому вы можете попасть в беду, например, прочитав поле в конструкторе.)
  • PHP имеет некоторые запутанные поведения, связанные с магическими методами - e. г. empty($entity->field) не будет вызывать __get (и, таким образом, это нарушит поведение прокси-сервера, если оно используется)
person Tgr    schedule 07.06.2012
comment
Кстати: empty($entity->field) вызовет магический метод __isset(), который предполагается использовать в документации. - person feeela; 01.06.2016

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

Таким образом, API чище, без магии. Я не люблю магию в своем коде.

Просто мои два цента :)


Под "свободным сеттером" я подразумевал тот, который реализует шаблон свободного интерфейса.

person xPheRe    schedule 27.12.2010
comment
Что такое «беглый сеттер»? Можете ли вы отредактировать свой ответ и добавить ссылку или что-то в этом роде? - person rjmunro; 16.12.2011
comment
Таким образом, в основном сеттер, который заканчивается return $this;, поэтому вы можете выполнять цепочку, подобную jQuery: $object->setName('name')->setCode('code');. Хорошая идея. Было бы неплохо добавить это в сеттеры, сделанные инструментом orm:generate-entities. - person rjmunro; 19.12.2011

Да, методы получения и установки - это способ доступа к вашим данным. Они немного громоздки, поэтому некоторым людям не нравится доктрина2 или спящий режим. Но вам нужно сделать это только один раз для каждой сущности, и тогда они будут очень гибкими для создания форматирования вывода, на которое вы надеетесь. Вы можете использовать cli, чтобы сделать это за вас. Но когда вы заставляете их вращаться, я не нахожу это большим делом. Тем более, что вы делаете это только с теми свойствами, которые вам нужны.

Ваше здоровье

person Richard    schedule 16.12.2010

Вместо того, чтобы иметь отдельные геттеры и сеттеры или даже использовать магические функции. Есть ли проблема с наличием чего-то подобного в классе

public function Set($attrib, $value)
{
    $this->$attrib = $value;    
}

public function Get($attrib)
{
    return $this->$attrib;
}   

Это упрощает доступ к атрибутам и означает, что они динамически устанавливаются из массивов пар ключей.. есть комментарии? или альтернативные предложения?

person KW1    schedule 14.01.2012

Doctine 2 предоставляет [инструмент командной строки][1] для создания базовых классов сущностей.

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

path/to/doctrine_cli orm:generate-entities --generate-methods=true path/to/entities/

Вы по-прежнему несете ответственность за изменение каждого метода получения/установки, чтобы гарантировать, что они являются правильным типом данных, поскольку методы получения/установки, сгенерированные для Entity, не выполняют приведение/преобразование типов.

person Mars Redwyne    schedule 14.12.2011