Объектно-ориентированный PHP Best Practices - PullRequest
9 голосов
/ 09 марта 2010

Скажем, у меня есть класс, который представляет человека, переменная в этом классе будет $ name.

Ранее в моих сценариях я создавал экземпляр объекта, а затем устанавливал имя, просто используя:

$object->name = "x";

Однако мне сказали, что это не лучшая практика? Чтобы у меня была функция set_name () или что-то похожее на это:

function set_name($name)
{
    $this->name=$name;
}

Это правильно?

Если в этом примере я хочу вставить новую запись о человеке в базу данных, как передать всю информацию о человеке, например, $ name, $ age, $ address, $ phone и т. Д., вставить его, я должен сделать:

function set($data)
{
    $this->name= $data['name'];
    $this->age = $data['age'];
    etc
    etc

}

Тогда отправьте это массив? Будет ли это лучшей практикой? или кто-то может порекомендовать лучшую практику?

Ответы [ 6 ]

29 голосов
/ 09 марта 2010

У вас должны быть методы установки / получения. Они - боль, но вам не обязательно писать их самим. IDE (например, Eclipse или Netbeans) может генерировать их для вас автоматически, если вы предоставляете члена класса. Если, однако, вы вообще не хотите иметь дело с этим и используете PHP5, вы можете использовать его магические методы для решения этой проблемы:

   protected $_data=array(); 
   public function __call($method, $args) {
        switch (substr($method, 0, 3)) {
            case 'get' :
                $key = strtolower(substr($method,3));
                $data = $this->_data[$key];
                return $data;
                break;
            case 'set' :
                $key = strtolower(substr($method,3));
                $this->_data[$key] = isset($args[0]) ? $args[0] : null;
                return $this;
                break;
            default :
                die("Fatal error: Call to undefined function " . $method);
        }
    } 

Этот код будет запускаться каждый раз, когда вы используете несуществующий метод, начиная с set или get. Теперь вы можете устанавливать / получать (и неявно объявлять) переменные следующим образом:

$object->setName('Bob');
$object->setHairColor('green');

echo $object->getName(); //Outputs Bob
echo $object->getHairColor(); //Outputs Green

Нет необходимости объявлять члены или функции установки / получения. Если в будущем вам нужно добавить функциональность в метод set / get, вы просто объявляете его, по существу, переопределяя магический метод. Также, так как метод setter возвращает $ this, вы можете chain их так:

 $object->setName('Bob')
        ->setHairColor('green')
        ->setAddress('someplace');

, что облегчает написание и чтение кода.

Единственным недостатком этого подхода является то, что он усложняет распознавание структуры вашего класса. Так как вы по сути объявляете члены и методы во время выполнения, вы должны выгрузить объект во время выполнения, чтобы увидеть, что он содержит, а не читать класс. Если вашему классу нужно объявить четко определенный интерфейс (потому что это библиотека и / или вы хотите, чтобы phpdoc генерировал документацию API), я настоятельно рекомендую объявлять открытые методы set / get вместе с приведенным выше кодом.

21 голосов
/ 09 марта 2010

Использование явных методов получения и установки для свойств объекта (как пример, который вы дали для set_name) вместо прямого доступа к ним дает вам (среди прочего) следующие преимущества:

  • Вы можете изменить «внутреннюю» реализацию без необходимости изменять какие-либо внешние вызовы. Таким образом, «внешний» код не нужно менять так часто (поскольку вы предоставляете согласованные средства доступа).
  • Вы очень четко указываете, какие свойства предназначены для использования / вызова извне класса. Это окажется очень полезным, если другие люди начнут использовать ваш класс.

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

6 голосов
/ 09 марта 2010

Я полностью согласен с CristopheD (проголосовал). Я просто добавил бы хорошую практику при создании нового человека .

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

class Person
{
  private $name;
  private $surname;
  private $sex;

  // Male is the default sex, in this case
  function Person($name, $surname, $sex='m'){
    $this->name = $name;
    $this->surname = $surname;
    $this->sex = $sex;
  }

  // Getter for name
  function getName()
  {
    return $this->name;
  }

  // Might be needed after a trip to Casablanca
  function setSex($sex)
  {
     $this->sex = $sex;
  }
}

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

4 голосов
/ 09 марта 2010

Чтобы пройти полный ООП, вы должны сделать что-то похожее на:

class User {

private $_username;
private $_email;

public function getUsername() {
    return $this->_username;
}
public function setUsername($p) {
    $this->_username = $p;
}
...
public function __construct() {
    $this->setId(-1);
    $this->setUsername("guest");
    $this->setEmail("");
}
public function saveOrUpdate() {
    System::getInstance()->saveOrUpdate($this);
}
}

Если вы хотите сохранить пользователя, вы просто создаете его, присваиваете его значения с помощью Setters и делаете $ user-> saveOrUpdate (), и имеете другой класс для обработки всей логики сохранения.

2 голосов
/ 09 марта 2010

В качестве контрапункта к ответу ChristopheD, если ваша переменная экземпляра предназначена исключительно для частного использования, я бы не стал писать геттер и сеттер, а просто объявил бы переменную экземпляра private.

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

Кроме того, использование getter / setter также ограждает другие части того же класса от знания о его собственной реализации, что я нашел иногда очень полезным!

1 голос
/ 09 марта 2010

С более общей точки зрения как прямой доступ ($ person-> name), так и методы доступа ($ person-> getName) считаются вредоносными. В ООП объекты не должны делиться какими-либо знаниями об их внутренней структуре, а только выполнять сообщения, отправленные им. Пример:

// BAD

function drawPerson($person) {
  echo $person->name; // or ->getName(), doesn't matter
}

$me = getPersonFromDB();
drawPerson($me);

// BETTER

class Person ....
   function draw() {
       echo $this->name;
    }

$me = getPersonFromDB();
$me->draw();

больше чтения: http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html

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