Второй подход, как вы говорите, более правильный, согласно ООП. Вы также правы, что с точки зрения циклов ЦП при вызове метода больше затрат, чем при обращении к свойству как к переменной. Однако в большинстве случаев это относится к категории микрооптимизации. Это не окажет заметного влияния на производительность, за исключением случаев, когда рассматриваемое значение интенсивно используется (например, в самой внутренней части цикла). Передовой опыт имеет тенденцию отдавать предпочтение правильному, а не самому высокопроизводительному, если только результат не страдает из-за этого.
Для простых переменных использование геттера внутри не сразу очевидно, но метод вступает в свои права, если вы имеете дело со свойством, которое заполняется из внешнего источника данных, такого как база данных. Использование метода получения позволяет вам извлекать данные из БД ленивым способом, то есть по требованию, а не до того, как это потребуется. Например:
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 никогда не вызываются, поиск в базе данных не выполняется. Это приведет к большому выигрышу в производительности, так как поиск в базе данных стоит дорого, и его следует избегать, где это возможно.
Это может привести к некоторым проблемам, если вы работаете в классе, который может обновлять базу данных, но это не сложно обойти. Если класс обновляет свое состояние, тогда ваши установщики могут быть просто закодированы, чтобы они обнуляли свое связанное состояние при успешном завершении. Таким образом, данные будут обновлены из базы данных при следующем вызове геттера.