Putting HTML to Work
At some point in OOP development with PHP, I quit putting little PHP code snippets in HTML. I either left all PHP out of HTML or encapsulated HTML in a PHP heredoc string inside a class. In that way, all PHP would be part of an OOP order without any loose ends. That may seem overly fussy, but it avoids the slippery slope of degenerating back into sequential programming——patchwork quilt programming.
However, such a practice should not disallow HTML from helping out in an OOP project. A lot of times, I found myself sifting through class and method options using more conditional statements than I wanted in the Client. I realized that I could just pass the class name directly to the Client from a superglobal with origins in an HTML input form. Likewise, I could do the same for methods, and this has become a useful standard operating procedure.
To better illustrate using the HTML UI in launching a selected class object, the following application uses the color and number input elements with both class and method information stored in HTML element values. Both are trivial, but help illustrate the point: (Use Firefox, Chrome or Opera–neither Safari nor Internet Explorer implemented the HTML5 standard color input element.)
It’s odd in a way that PHP developers (myself included) are so used to using HTML UIs for data input into MySql databases or making other choices, but few use the UI for calling classes and methods. However, it’s both easy and practical.
Where to Put the OOP in HTML?
You can place class and method names as values anywhere in form inputs that you’d put any data passed to PHP as superglobals. One input form I found useful is the hidden one. It’s out of the way, and you can build forms around the class with other superglobal inputs as methods. Using radio button inputs is another nice option because you can use them either for calling classes or methods with the mutual exclusivity assurance of knowing that not more than one will be called from a given group. To get started, take a look at the HTML:
|
The code has two forms, alpha and beta, and you can think of them as I/O for two different classes. The feedback is returned to the iframe named feedback. Both forms have the action calls to Client.php. So the general plan is:
Client → Class->method()
In the alpha form, the class is ColorClass and the method is doColor()—both in hidden input elements. The name for the class element is “class” and the name for the method element is “method.” All the user does is to choose a color that is passed through the superglobal associated with the color input element.
In the beta form, the class is MathClass placed in a hidden input element. The user chooses either a division or modulo operation from the two radio input elements where the names of the appropriate methods are stored. Once again, the name for the class element is “class” and with mutually exclusive choices the radio button elements for selecting the method, the name is “method.” In this way, whatever superglobal named “class” will fire the correct class and call the correct method with the superglobal named “method.”
The Client
As usual, the Client is the launching pad for the operations. If your application uses different client classes depending on user choices, it’s an easy matter to have unique client names for different forms. In this particular case, the Client class doesn’t care about the form of origin for the request. It just takes the class superglobal and method superglobal names and generates a call to the appropriate class and method.
As an aside, the Client in OOP should not be as rare as some perceive it to be. In one way or another, users (or non-human request mechanisms) employ some way to request that the software do something. The Client, as a participant in a structure, is in virtually every design pattern in one way or another. Even when the Client is not directly or implicitly in a design pattern, The Gang of Four reference it as related to one of the participants in the pattern. So while this example does not use a design pattern, the Client works perfectly well in any OOP program.
/*
* Set up error reporting and
* class auto-loading
*/
error_reporting(E_ALL | E_STRICT);
ini_set("display_errors", 1);
// Autoload given function name.
function includeAll($className)
{
include_once($className . '.php');
}
//Register
spl_autoload_register('includeAll');
//Class definition
class Client
{
private static $object, $method;
//client request
public static function request()
{
self::doSuper();
$operation = new self::$object();
echo $operation->{self::$method}();
}
private static function doSuper()
{
self::$object = $_POST['class'];
self::$method=$_POST['method'];
unset($_POST['class']);
unset($_POST['method']);
}
}
Client::request();
?>
|
The Client file first takes care of error reporting and automatically calling classes. One experienced developer told me that adding an error-reporting function was unnecessary because it could be automatically turned on in the php.ini file. That’s true, but since I work with many different PHP environments where I have no control over the php.ini file, I’ve found it to be a good practice. You only have to put it in once place, and it takes care of error reporting for the entire program. Besides, I found that one safeguard against easy hacking is to turn off error reporting so that hackers cannot see the names of the classes involved in the application. For this blog, though, I leave the error reporting on because there’s nothing on this blog I want to hide. (Change the init_set from “1” to “0” to turn off all error-reporting.)
No Returns from Constructor Functions
The first incarnation of this application used the same two forms, but the alpha form only had the class name with the results planned to be sent back for output using a return statement. I kept getting errors, and then I learned that constructor functions (those using the __construct() method) have no returns. All they do is to instantiate the class. If you do not use the __construct() method, there’s an invisible automatic constructor function that does that for your as soon as you call new ClassName().
So, if you want a return, you need to have a public method that gathers up returned data. Now, before you think, “A constructor function is perfectly capable of outputting results using an echo, printf() or some similar I/O statement. However, the idea is to get returned information to format and output from somewhere other than the object that generated the information. (The Functional Programmers refer to all I/O as side-effects and caution against using them unless that is the function of the operation.)
As a result of this wisdom, all of the I/O in this humble application is handled by the Client. It just echos out whatever is returned from the call. As long as it’s returned, it can be used for anything the developer has in mind. In the first case, it’s the color in the superglobal, ‘colorNow.’
class ColorClass
{
private $color;
public function doColor()
{
$this->color=$_POST['colorNow'];
unset($_POST['colorNow']);
return $this->color;
}
}
?>
|
All it does is to take the color code out of the superglobal and return it to the requesting object—the Client.
The other working class in the application, MathClass, does much the same, except the class has two methods: one for division, and one for modulo.
class MathClass
{
private $solution, $first, $second;
public function doModulo()
{
$this->doSuper();
$this->solution=$this->second % $this->first;
return $this->solution;
}
public function doDivide()
{
$this->doSuper();
$this->solution=$this->second / $this->first;
return $this->solution;
}
private function doSuper()
{
$this->first=$_POST['first'];
$this->second=$_POST['second'];
unset($_POST['first']);
unset($_POST['second']);
}
}
?>
|
You may have noticed that both the Client and MathClass include a doSuper() method. This method is designed to pass the superglobal values to variablse and then clear the superglobals. In this way you won’t have any loaded superglobals wandering around and you can insure that any data in the superglobals is newly passed. The single superglobal in the ColorClass is unset right after its assigned to the $color property.
Why Avoid Conditional Statements in OOP?
A lot of times I find myself in untested habits that are supposed to be “good practices,” but upon closer examination may not be. For example, you could use if(isset…) until you’re blue in the face, and not have a lot of difference between having that conditional and nothing at all. What if something isn’t set? Will having if(isset…) make a difference? If your program is expecting anything from a set superglobal, what will happen if it’s not set? Your program will fail. You can use the Exception class and try/catch to test a condition, but try/catch is a form of a conditional, and while I prefer it to using if(…), my preference if not to use any conditionals without a compelling reason to do so. In fact, I’ve come up with an OOP programming principle regarding conditional statements:
Don’t use conditional statements when you have better alternatives.
If you look at the interacting classes in this sample app, you’ll see no conditionals, and everything works as expected. As you may know, neither the State nor Strategy patterns use conditionals. The advantages are many:
- Easier to debug
- Clearer code
- Faster execution
- Easier Reuse
One way to help avoid conditionals is to add class and method information in the HTML UI. In that way the Client does not have to sort out which class and method to launch using conditional statements.
If you look at the post on algorithms on this blog, you’ll see that quadratic algorithms based on double loops are not recommended. Since all loops are a form of conditional statements insofar as they contain conditionals for loop-ending states, the caution applies to conditionals as well. Nested conditionals are the worst, and while some think they represent sophisticated programming, they’re the opposite.
This is not to say, you should never use conditionals or loops, including nested ones. Rather, it’s an encouragement to stop and consider alternatives. In lambda functions, you’ll find elegantly written conditionals, especially in the form of recursions. Instead of nested loops, consider logarithmic algorithms, and while containing a loop, they avoid an added nested loop. Further, instead of a testing conditional, use the Exception class and the try/catch/finally blocks.
To repeat, this is not an advocacy to ban conditionals or loops, but rather to consider alternatives to both. A little better planning at the outset can lead to better object oriented coding, easier refactoring and in creating reusable code. All of this starts with,
Put the HTML UI Couch Potato to OOP Work!
Copyright © 2015 William Sanders. All Rights Reserved.
0 Responses to “PHP Class Origins: An OOP Job for the HTML UI”