PHP Memoization

One of my favorite optimization techniques is memoization.  Memoization is a technique used to store commonly used calculations in memory.

Let's say we are working with PHP and using object oriented programming.  We are working on an application that has a people class.  The people class has 3 properties called name, age, and location.

<?php

    class people {
        
        public $name;
        public $age;
        public $location;
        
    }

?>

We would then create methods to retreive the parameters from the people object.

<?php

    class people {
        
        public $name;
        public $age;
        public $location;
        
        public function getName($personId) {
            
        }
        
        public function getAge($personId) {
        
        }
        
        public function getLocation($personId) {
        
        }
        
    }

?>

Now let's add a final method that will perform a database look for the requested attribute.

<?php

    class people {
        
        public $name;
        public $age;
        public $location;
        
        public function getName($personId) {
        
            return $this->_data('name', $personId);
        
        }
        
        public function getAge($personId) {
        
            return $this->_data('age', $personId);
        
        }
        
        public function getLocation($personId) {
        
            return $this->_data('location', $personId);
        
        }
        
        private function _data($field, $personId) {
            
            //Establish Database Connection
            $pdo = new PDO("mysql:host=$host;dbname=$database",$user,$pass);
            
            //Build our query
            $sql = "SELECT `$field`
                FROM `people`
                WHERE `id` = ?";
            
            //Prepared statement and assign variables
            $query = $pdo->prepare($sql);
            $query->execute(array($personId));
            
            $results = $query->fetchAll(PDO::FETCH_ASSOC);
            
            //Return the database result
            return $results[$field];
            
        }
        
    }

?>

The above code will work fine, but will query the database every time you ask for a person's age, name, or location.

What if we were to create another property of the people class that would store the person's information?  Then, any consecutive calls to the get methods would return a value stored in memory and eliminate a database query.

<?php

    class people {
        
        public $name;
        public $age;
        public $location;
        public $_data = array();
        
        public function getName($personId) {
        
            return $this->_data('name', $personId);
        
        }
        
        public function getAge($personId) {
        
            return $this->_data('age', $personId);
        
        }
        
        public function getLocation($personId) {
        
            return $this->_data('location', $personId);
        
        }
        
        private function _data($field, $personId) {
            
            //Memoization.  Return the value, if stored in memory.
            if( isset($this->_data[$personId][$field]) ){
                return $this->_data[$personId][$field];
            }
            
            //No value found in memory, so perform database lookup.
            
            //Establish Database Connection
            $pdo = new PDO("mysql:host=$host;dbname=$database",$user,$pass);
            
            //Build our query
            $sql = "SELECT *
                    FROM `people`
                    WHERE `id` = ?";
            
            //Prepared statement and assign variables
            $query = $pdo->prepare($sql);
            $query->execute(array($personId));
            
            $results = $query->fetchAll(PDO::FETCH_ASSOC);
            
            //Store the person data in a local property
            $this->_data[$personId] = $results;
            
            //Return the database result
            return $results[$field];
            
        }
        
    }

?>

There are 3 main changes to the code above.  First of all, we added the $_data property to the people class.  This array is used in the _data() function to store person information.  The second change is the logic found at the beginning of _data() method, which checks if data has been stored in the local $_data variable for the given $personId.  Finally, we store the database resultset in the $_data array, using the $personId as the array key.

The final result is a single query that retrieves all database table fields for the given $personId and stores the results in local array.  Any consecutive calls to the _data() method, will check the local array for an existing value and either return the found array element or query the database to set the array element.

Of course, further optimization can be done to this code, but is outside the scope of this article.

Tags: php development