использовать класс getters или свойства класса?(PHP) - PullRequest
5 голосов
/ 31 декабря 2011

Что считается наилучшей практикой написания классов ООП, когда дело касается внутреннего использования свойства.

Рассмотрим следующий класс;

<?php
Class Foo
{
    /**
     * @var null|string
     */
    protected $_foo;

    /**
     * @return null|string
     */
    public function getFoo()
    {
        return $this->_foo;
    }

    protected function _doSomething()
    {
        $foo    = $this->_foo;
        $result = null;
        // ...
        return $result;
    }
}

Как вы видите, я использую свойство _foo в _doSomething () хотя подкласс может переопределить getFoo (), возвращая вычисленное значение, не сохраненное обратно в _foo;это недостаток.

Что мне делать?

  1. пометить получатель как окончательное, использовать свойство внутренне (без дополнительных вызовов функций, принудить конечного разработчика использовать _foo как свойство, так как этоЗащищено)
  2. внутренне используйте getFoo (), пометьте _foo как личное (вызовы дополнительных функций)

Оба варианта являются водостойкими, однако я серьезно обеспокоен всеми вызовами дополнительных функций, поэтому я склонениспользуйте вариант 1, однако вариант 2 будет более «истинным ООП» imho.

Также прочитайте http://fabien.potencier.org/article/47/pragmatism-over-theory-protected-vs-private, что также предлагает вариант 2: /

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

1 Ответ

5 голосов
/ 31 декабря 2011

Второй подход, как вы говорите, более правильный, согласно ООП. Вы также правы, что с точки зрения циклов ЦП при вызове метода больше затрат, чем при обращении к свойству как к переменной. Однако в большинстве случаев это относится к категории микрооптимизации. Это не окажет заметного влияния на производительность, за исключением случаев, когда рассматриваемое значение интенсивно используется (например, в самой внутренней части цикла). Передовой опыт имеет тенденцию отдавать предпочтение правильному, а не самому высокопроизводительному, если только результат не страдает из-за этого.

Для простых переменных использование геттера внутри не сразу очевидно, но метод вступает в свои права, если вы имеете дело со свойством, которое заполняется из внешнего источника данных, такого как база данных. Использование метода получения позволяет вам извлекать данные из БД ленивым способом, то есть по требованию, а не до того, как это потребуется. Например:

class Foo
{
    // All non-relevent code omitted
    protected $data = NULL;

    public class getData ()
    {
        // Initialize the data property
        $this -> data = array ();
        // Populate the data property with a DB query
        $query = $this -> db -> prepare ('SELECT * FROM footable;');
        if ($query -> execute ())
        {
            $this -> data = $query -> fetchAll ();
        }
        return ($this -> data);
    }

    public function doSomethingWithData ()
    {
        $this -> getData ()
        foreach ($this -> data as $row)
        {
            // Do processing here
        }
    }
}

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

class Bar
{
    // All non-relevent code omitted
    protected $data = NULL;

    public class getData ()
    {
        // Only run the enclosed if the data property isn't initialized
        if (is_null ($this -> data))
        {
            // Initialize the data property
            $this -> data = array ();
            // Populate the data property with a DB query
            $query = $this -> db -> prepare ('SELECT * FROM footable;');
            if ($query -> execute ())
            {
                $this -> data = $query -> fetchAll ();
            }
        }
        return ($this -> data);
    }

    public function doSomethingWithData ()
    {
        foreach ($this -> getData () as $row)
        {
            // Do processing
        }
    }
}

В этой версии вы можете вызывать doSomethingWithData (и, действительно, getData) так часто, как захотите, вы никогда не будете запускать более одного поиска в базе данных. Кроме того, если getData и doSomethingWithData никогда не вызываются, поиск в базе данных не выполняется. Это приведет к большому выигрышу в производительности, так как поиск в базе данных стоит дорого, и его следует избегать, где это возможно.

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

...