Tips for PHP Developers Pt. 2 Focus on Modularity
April 12, 2006
Part two of this series I am focusing on a subject as the first time I did not. This post will focus primarily on modularizing an application and its components.
Prefix your functions and classes
Another big thing is many people do not prefix their functions and/or classes. This is very important otherwise you can run into naming conflicts. Take for instance you just spent a day writing and implementing a class in several different files only to find out that there is already a class used by PHP or PEAR that causes this to not work in different environments. Now you have to go through all of the files and replace this with the new naming and retest. Yes there are search and replace functions in just about any text editor but for design sakes PLEASE prefix your classes!
A good example of this is the PEAR Date class. A while back there was a big issue with a naming conflict that caused a date class to not be included by default into php. Take this as a serious warning!
Checking for defined constants before setting a constant
I am a huge fan of constants for items like regular expressions, mostly because the pattern will probably not change and I want to use pretty much the same pattern through out a whole site. Now I also define these in the class file itself which allows to basically set a default.
Now these default constants are mainly in place to set the constant if there is not one previously defined. This allows for great flexibility seeing as I use an email regular expression in around 5 or 6 places. PHP has the most wonderful function “defined()” which allows you to check if something has already been defined. So if someone came along and wanted to override that regular expression they could simply define it before it was defined. For those that need something a little more see the following example of how I normally do this:
//validate_telephone.class.php if (!defined('REGEX_US_TELEPHONE') { define('REGEX_US_TELEPHONE', '/^\(?([0-9]{3})\)?[\s\.\-]*([0-9]{3})[\s\.\-]*([0-9]{4})$/'); } class dsValidateTelephone extends dsValidate { public function validate($tele) { if (preg_match(REGEX_US_TELEPHONE, $tele)) { return true; } return false; } } //someform.php define('REGEX_US_TELEPHONE', 'mycustomregex');
As you can see this can be extremely useful….
Using a database abstraction library
If you are not currently using a database abstraction library there are several reasons to do so. The main advantage is you can deploy to more than a single database and if you ever move databases there is hardly any code that requires you to modify the current functionality. Also most of these abstraction libraries allow you to debug the queries to the database much better than if you were to use the API’s method for retrieving database error messages and numbers.
There are several database abstraction libraries out there. If you are using PHP 5 definitely use PDO. For PHP 4 I would say to use PEAR DB, ADODB or ADODB Lite.
Writing a renderer with formatted strings for output that could be changed by a user
One of my personal pet peeves is when there is a class that outputs a string or content that I can not customize without destorying the class or heavily rewriting it. One of the things that HTML_QuickForms got right was how they provide an interface to modify the output that it produces. By simply extending a class and setting those variables you are set to go. Say for instance we have a class that returns a string used for output that we use for providing links from a datbase (I will provide a PHP4 and PHP5 example since most people are still running it):
//php4 class LinkRenderer { var $enclose = '<ul>%s</ul>'; var $tag = '<li><a href="%s">%s</a></li>'; var $_links = array(); function addLink($url, $text) { $this->_links[] = array($url, $text); } function toHTML() { $output = ''; while(list(,$l) = each($this->_links)) { $output .= sprintf($this->tag, $l[0], $l[1]); } return sprintf($enclose, $output); } } //php5 class LinkRenderer { public $enclose = '<ul>%s</ul>'; public $tag = '<li><a href="%s">%s</a></li>'; protected $_links = array(); public function addLink($url, $text) { $this->_links[] = array($url, $text); } public function toHTML() { $output = ''; while(list(,$l) = each($this->_links)) { $output .= sprintf($this->tag, $l[0], $l[1]); } return sprintf($enclose, $output); } }
Grouping code that is reused into functions or classes
The main point of this is to keep maintenance time down. If there is a small bug the developer no longer needs to run through all of the code and try to find exactly every place that this code was copied or written. Even although this is a novice mistake, I see it come up extremely often when reviewing other peoples code.
Checking for php version and functions before usage
Sometimes you will deal with circumstances where different versions of php implement functions you need or there are restrictions on certain functions and you would like to implement the function yourself. Here is an examples:
//implement file_put_contents if not php5 or function doesn't exist: if (!function_exists('file_put_contents') || version_compare(PHP_VERSION, "5", "< ")) { function file_put_contents($filename, $data) { if (is_writable($filename)) { $fp = fopen($filename, 'w'); $ret = fwrite($fp, $data); $fclose($fp); return $ret; } return false; } }
In the upcoming part 3 I will focus on some simple security tricks that should help you lock down your code.
Tips for PHP Developers Pt. 1
April 12, 2006
Every seasoned developer has their tricks of the trade. My good friend and I normally will sit down and talk about web development. We focus normally on security, performance and the best way to do things. I will be posting probably 2 or 3 more tips sections, however since I have limited time here are a few to start!
When checking for an empty string use $str==” or strlen($str)
You should do this because using empty() would return false for a string with the number 0. This is probably not an expected thing that happens.
Do not store escaped output in the database (htmlentities or htmlspecialchars)
This can be a very touchy one for some developers. You should not do this because if you escape some html characters you are now using more characters in the database where it should have allowed to store the full string and lead to user confusion why it didn’t store the whole string after entering it in to the maxlength of a text input. Another reason being, what if you chose to not only use this databases data for the web but for a desktop application or PDF? Now you need to decode the escaped data.
Use Casting to speed up and check input
When you are checking numbers you can cast them to check them quicker and not have to utilize a function call. Take the following:
if ($id = (int) $_GET['id']) { //will evaluate to true if the number is greater than 0. }
You can do the same things with floats, arrays and objects. However you will need to do more validation if it isn’t a number.
Using while(list($k,$v) = each($array)) instead of foreach($array as $k=>$v)
You should do this while iterating through an array because foreach creates a copy instead of actually iterating through the array. Still use foreach if you are using objects. If you are going to need to reuse this array make sure to call reset($array) otherwise you can’t iterate the array!
Use a Singleton Patterns
If you are using a database this is highly beneficial so that you aren’t using the global keyword to pass the connection into a function and also for keeping memory down. See the example for a PHP 4 implementation for a singleton:
class singleton { function &singleton($class) { static $_instances; if (!is_array($_instances)) { $_instances = array(); } if (!isset($_instances[$class])) { $instances[$class] =& new $class; } return $instances[$class]; } } $myclass =& singleton('stdObject');
Use static class methods to group functions
If you have a bunch of functions related to one thing you can group them all in a class and call them statically so they are essentially in a namespace. This helps so you do not clutter the global scope. This also helps with possble naming conflicts. Example:
class myTypes { function get_type($var) { //... } function check_type($var, $check) { //... } function set_type($var, $type) { //... } } $var_get_type = myTypes::get_type($var);
I hope these are helpful for you, feel free to leave comments with additional tips or questions that you may have that I can cover in the next tips blog!
PHP Implementation of Test::More
April 7, 2006
Lately I have been looking at the PHP Test::More implementation that Chris Shiflett has been writing. I must say it is extremely easy compared to testing with the larger testing frameworks. However I do believe it has it’s drawbacks which I will get to a little later. Test::More is actually a perl implementation brought to us by Apache. It is an amazingly simple testing tool for your code that doesn’t take you such an incredible amount of time to run a test on everything. Which I guess that is fantastic news to us developers.
Testing is one of those things that absolutely needs to be done. With out it you may run into logic errors and syntax errors that may be hidden. Allowing yourself to test what certain variables should be allows you to significantly lower those types of issues. These types of tests do not help you with writing secure applications, ensuring code quality nor anything else that is around that area. In essence it just allows you to test that all of your code “works”.
What I like about Test::More is that I can test my applications very quickly rather than writing huge unit tests that take up essential time in getting a project done on time and under budget. I also like that the syntax is extremely easy to write and understand quickly if another developer was to ever encounter the test cases. It also implements TAP (Test Anything Protocol). Which makes it very nice to move on to a different testing framework that might encorporate it in the future.
What I did not like about the PHP implementation of Test::More was that there is no function to iterate through an array. Since you would probably be checking the same items in that array, you may only want to output the pass or failure one time instead of multiples. Meanwhile I see why because this starts to take it away from the KISS (Keep It Simple Stupid) way. Next was that it did not prefix variables or prefix functions. Sometimes some software projects use bad naming and I feel this might cause a conflict. Instead of the developer of that project adapting and changing how their application works they will more than likely drop the tester and continue on. Last but not least is that I feel output could infact use varables as a means of an output template for each specific item. This would allow for more flexibility on how the output could be rendered. Allowing developers and/or companies to integrate it tighter into their testing needs.
What would a post be without an actual example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | include('test-more.php'); class preUser { private $_id; public function getId() { if ($this->_id = (int) $this->_id) { return $this->_id; } return false; } public function setId($id) { if ($id = (int) $id) { $this->_id = $id; return true; } return false; } } plan(2); $user = new preUser; ok($user->setId(1), 'Testing setId()'); is($user->getId(), 1, 'Testing getId() matches what we set'); |
This outputs:
1..2
ok 1 - Testing setId()
ok 2 - Testing getId() matches what we set



