The second approach, as you say, is the more correct path according to OOP. You are also right that calling a method has more costs in terms of CPU cycles than accessing a property as a variable. However, in most cases this belongs to the category of micro-optimization. This will not have a noticeable effect on performance, except that the value in question is heavily used (for example, in the innermost part of the loop). Best practice, as a rule, contributes to the correct work on the most productive, if as a result of this performance will not really suffer.
For simple variables, using a getter internally is not immediately obvious, but the method comes to your senses if you are dealing with a property that is populated from an external data source, such as a database. Using a getter allows you to retrieve data from the database in a lazy way, that is, on demand, and not earlier than necessary. For instance:
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 } } }
Now with this approach, every time you call doSomethingWithData, the result is a call to getData, which in turn executes the database query. It is wasteful. Now consider the following similar class:
class Bar {
In this version, you can call doSomethingWithData (and indeed getData) as often as you like, you will never run more than one database lookup. In addition, if getData and doSomethingWithData are never called, database searches are never performed. This will lead to a big performance gain, as finding a database will be expensive and should be avoided whenever possible.
This leads to some problems if you work in a class that can update the database, but it is not difficult to work around. If a class makes updates in its state, your installers can simply be encoded so that they successfully delete the state associated with it. Thus, the data will be updated from the database the next time the recipient is called.