Using Static Variables in PHP 5 Classes

In this first part of a four-part series, I show you how the declaration and further use of a single static property inside a MySQL abstraction class can be really useful for turning this class into a Singleton. While it’s fair to say that you can use different approaches for implementing this design pattern, most of them will employ a static variable.

Without starting a debate about the strengths and weaknesses of PHP 5, I’d like to say that the language, with all its cons and pros, has reached a great level of maturity, particularly when it comes to evaluating its highly-enhanced object model.

Well-known improvements like member visibility and abstract classes, coupled to a native support for interfaces and exceptions, just to name a few examples, provide developers with a set of powerful characteristics that allow them to build more complete object-oriented web applications. Best of all, they can do this without needing to appeal to tricky and dirty programming hacks, used pretty frequently in the bad old days of PHP 4.

Of course, with the variety of eye-catching features packaged behind a friendly API, it’s not surprising to see that the use of static variables has been delegated in many cases to the entrance of a humble backdoor. In reality, static variables (or class-level variables, as some programmers use to say in meetings to create a stronger impression on the people around them) are indispensable, especially if your PHP programs implement some common design patterns such as Singleton and Lazy Loading.

Naturally, as with many other native features of PHP, when misused or overused, static variables can lead quickly to poorly-written, messed-up code, which can be a nightmare to maintain and scale. But, as you may guess, this is simply a consequence of their bad usage and not of the variables’ intrinsic nature.

As I said a moment ago, static variables can be really helpful when used in a clever way, and to prove that, in this group of articles I’m going to show you how to utilize them in the development of a basic – yet functional — MySQL driver. This driver, through a simple set of methods, will permit us to perform a few handy operations against a selected database, such as running queries, manipulating data sets, and so forth.

The didactic facet of this experience won’t be building a driver like this; instead, it’ll be aimed at demonstrating how the use of some static variables can  remarkably improve the behavior of the driver.

Now, join me in this hopefully educational journey and start rediscovering the real power behind using static variables in PHP 5. Let’s jump in!

{mospagebreak title=Building a sample MySQL driver}

In order to demonstrate how the use of some static properties can actually improve the behavior of a given class, in the following lines I’m going to start building the MySQL driver mentioned in the introduction. In this particular case, it will act like a simple wrapper for the built-in MySQLi PHP 5 class.

Having explained my goal here, the initial definition of the wrapper will be as follows:

class MySQLiWrapper extends MySQLi

{

 

private $_config = array();

 

public function __construct(array $config)

{

if (count($config) < 4)

{

throw new Exception(‘Invalid number of connection parameters’);

}

$this->_config = $config;

}

 

// prevent cloning class instance

private function __clone(){}

 

// establish a connection to MySQL

public function connect()

{

list($host, $user, $password, $database) = $this->_config;

parent::__construct($host, $user, $password, $database);

if ($this->connect_error)

{

throw new Exception(‘Error connecting to MySQL : ‘ . $this->connect_errno . ‘ ‘ . $this->connect_error);

}

unset($host, $password, $database);

}

}

Well, that’s no much to begin with, but it’s better than nothing. As seen above, the previous "MySQLiWrapper" behaves exactly like a wrapper for the native MySQLi class that comes bundled with PHP 5. At this point, the class implements only two methods, its constructor and the public "connect()." The first one accepts an array of input parameters required for connecting to MySQL and selecting a specified database, and the last one performs the actual connection process.

So far, nothing interesting is happening with this class, as there’s no single sign that shows the use of a static property in it. However, since it’d be highly desirable to deal with only one instance of this driver, it’d be useful to turn it quickly into a Singleton class.

We can do this by declaring a static property that controls the proper instantiation of the driver. Therefore, in the section to come I’m going to enhance the definition of the previous "MySQLiWrapper" class by adding to it the aforementioned static property, along with a whole new method that will manipulate this variable in a clever way.

To learn more about this enhancement, click on the link below and read the following segment.

{mospagebreak title=Adding a Singleton static method}

In the previous section, I implemented the first two methods of a basic MySQL driver, whose underlying logic has been hopefully easy for you to grasp. At this point, the class doesn’t explicitly use any static property to improve its behavior. This is about to change.

Since in most cases a database handler object will be shared by other objects within the context of an application, the earlier driver is an excellent candidate for turning into a Singleton class. Of course, one can use several approaches to achieve this; in this example, I’m going to use a static property to assure that only one instance of the driver is always returned to client code.

Having said that, look at the enhanced version of the previous "MySQLiWrapper" class. This time, it implements a new static method called "getInstance()" that returns a Singleton instance of it by controlling the aforementioned static property:

class MySQLiWrapper extends MySQLi

{

 

private static $_instance = NULL;

private $_config = array();

 

// return Singleton instance of MySQL class

public static function getInstance(array $config = array())

{

if (self::$_instance === NULL)

{

self::$_instance = new self($config);

}

return self::$_instance;

}

 

// private constructor

private function __construct(array $config)

{

if (count($config) < 4)

{

throw new Exception(‘Invalid number of connection parameters’);

}

$this->_config = $config;

 

}

 

// prevent cloning class instance

private function __clone(){}

 

// establish a connection to MySQL

public function connect()

{

list($host, $user, $password, $database) = $this->_config;

parent::__construct($host, $user, $password, $database);

if ($this->connect_error)

{

throw new Exception(‘Error connecting to MySQL : ‘ . $this->connect_errno . ‘ ‘ . $this->connect_error);

}

unset($host, $password, $database);

}

}

Admittedly, after adding the brand new "getInstance()" static method to the MySQL driver, things are starting to look slightly more interesting. This method uses a static $_instance property as a flag which ensures that only a single instance of the driver can be created at runtime.

Even though the combination of a static property and a static factory method isn’t the only way to develop a Singleton class, the above code fragment does show in a nutshell how useful this type of property can be for implementing this popular design pattern.

All in all, now that this sample MySQL driver has been turned into a Singleton class, it’s time to make it a bit more functional; right now it’s only capable of connecting to the server and selecting a specified database. That’s not too much, really.

Thus, in the last section I’m going to give the driver the ability to perform SQL queries, finding insertion IDs and so forth by implementing a few additional methods. However, to learn more about how these will be defined, you’ll have to click on the link below and keep reading.

{mospagebreak title=Adding a method to perform SQL queries and more}

Since the MySQL driver that you saw earlier can only create a Singleton instance of itself, and establish a connection to the server, below I listed the finished version of it. It includes some extra methods that allow it to run SQL statements, retrieve insertion IDs and close the connection.

Here’s how the enhanced version of the driver now looks:

class MySQLiWrapper extends MySQLi

{

 

private static $_instance = NULL;

private $_config = array();

 

// return Singleton instance of MySQL class

public static function getInstance(array $config = array())

{

if (self::$_instance === NULL)

{

self::$_instance = new self($config);

}

return self::$_instance;

}

 

// private constructor

private function __construct(array $config)

{

if (count($config) < 4)

{

throw new Exception(‘Invalid number of connection parameters’);

}

$this->_config = $config;

 

}

 

// prevent cloning class instance

private function __clone(){}

 

// establish a connection to MySQL

public function connect()

{

list($host, $user, $password, $database) = $this->_config;

parent::__construct($host, $user, $password, $database);

if ($this->connect_error)

{

throw new Exception(‘Error connecting to MySQL : ‘ . $this->connect_errno . ‘ ‘ . $this->connect_error);

}

unset($host, $password, $database);

}

// perform query

public function runQuery($query)

{

if (is_string($query) AND !empty($query))

{

// lazy connect to MySQL

$this->connect();

// run the specified query

if ((!$this->real_query($query)))

{

throw new Exception(‘Error performing query ‘ . $query . ‘ – Error message : ‘ . $this->error);

}

return new MySQLi_ResultWrapper($this);

}

}

 

// get insertion ID

public function getInsertID()

{

return $this->insert_id;

}

 

// close database connection

public function __destruct()

{

$this->close();

}

}

Not too bad, considering that this class is only an introductory example, eh? As you can see, now the driver implements a whole new method called "query()" for running hard-coded SQL queries. This method is somewhat special, as it composes a whole new object named "MySQLi_ResultWrapper."

Quite possibly you’re wondering what the point is in spawning another object. Well, as you’ll see in the forthcoming tutorial, this object’s originating class will be used to manipulate result sets in a separate way, which helps to keep the code that connects to MySQL and runs queries isolated from the one that processes data sets.

But for the moment, I suggest you stay focused on the definition of the MySQL driver. It recreates a real-world case where a static property can be really useful for implementing the Singleton design pattern in a painless manner.

Final thoughts

In this introductory chapter of the series, I showed you how the declaration and further use of a single static property inside a MySQL abstraction class can be useful for turning this class into a Singleton. While it’s fair to say that there are different approaches that can be utilized for implementing this design pattern, most of them will employ a static variable.

Before I forget to mention it, you should notice that the "query()" method of the previous MySQLi wrapper creates an instance of a result set object. Naturally, the originating class of this object has not been defined yet, but this process will be covered in the course of the subsequent tutorial.

To learn more on this topic, don’t miss the next part!

[gp-comments width="770" linklove="off" ]

antalya escort bayan antalya escort bayan Antalya escort diyarbakir escort