I'm working on a PHP page. The core page has most of the code under one if statement, and the rest of the code under an "else" statement. I'm about to add a third option, "edit" which will make the page yet longer. What is a good strategy to break up the logic into more readable chunks? Subroutines? I've gotten used to OO through Java. Web scripting seems to make it too easy to get into overly long if / else blocks.
classes, functions, includes.
I like to put content modules that occur on more than one page into their own file and just use include_once() statements. For instance you can keep one php file for your page header and just reuse it on multiple pages.
also, make sure to learn about the __autoload function. it automatically loads classes only when needed.
If you can, check out the MVC design pattern.
You should be able to add a controller which you can group your actions under.
You could incorporate routing so a URL like this...
/user/edit
Would call this in PHP (simplified)...
$controller = new User;
$controller->edit();
Of course, you'd need to use variable function names to get that to work dynamically :)
long if-else is inevitable if you comparing multiple set of conditions
you can make use of switch statement
Or in PHP 5.3, goto has been introduced (beware of the dinosaur)
Or wrap the conditions inside a function/method
function lots_of_conditions($id, $type, $category)
{
if ($id==1) return 1;
if ($type=='member') return 2;
if ($category=='keyword') return 4;
return 8;
}
$status = lost_of_conditions($id=2, $type='x', $category='y');
switch ($status)
{
case 1: ...; break;
case 2: ...; break;
case 4: ...; break;
default: ...; break;
}
You've got some real design issues to consider. And MVC as suggested by alex is probably a good idea. You should consider what is common between these three cases, and you might find that they're differences can be accounted for with a few variables.
For the meantime, to avoid your spaghetti code, you can put each of these three cases into a function. I don't know if these functions just need to echo something, or need return values, or what, but you should be able to figure that out.
Among other things, you can either have these as functions in the same file (if this 'core' file has a class, consider making these member functions) or put them in a static class elsewhere. I'll show the static option.
class BodyFunctions
{
public static function one() {echo "this is what you now call the 'if' block";} //think of better names for these first two
public static function two() {echo "this is what you now call the 'else' block";}
public static function three() {echo "this is the edit part you want to add";}
}
And to call them from your 'core' page
BodyFunctions::$mode(); //where mode is 'one', 'two', or 'edit'. like the variable your if statements are currently based on
Or you can just add the functions to your core page like this, and call them with call_user_func
function one() {echo "this is what you now call the 'if' block";}
....
call_user_func($mode);
What I wouldn't recommend is putting these functions in a class you need to instantiate even though this class lacks any kind of state and the sole purpose of instantiation is to run the functions inside. Doing tihs unnecessarily is kind of a pet peeve of mine.
I can't stress enough that this should be considered an intermediate measure to avoid the if-else chain or switch situation you've got going on. Look into MVC or a more thorough solution.
Consider that PHP is usually hosted behind some web server that is already using a "Front Controller" pattern - Apache or Lighttpd or similar. If your file logic looks like this:
/dingbat.php
// local page setup, function definitions, etc...
function foo() { ... }
function bar() { ... }
function everything_else_useful_on_this_page() { ... }
print_standard_header($TITLE);
if ($mode == "edit") {
do_edit_lots_of_hairy_logic();
} else if ($mode = "new thing") {
who_knows();
}
else {
print_form();
}
print_standard_footer();
...you can replace it with a set of files that look like this:
/dingbat/common.php
function foo() { ... }
function bar() { ... }
function everything_else_useful_on_this_page() { ... }
/dingbat/edit.php
include "common.php"
print_standard_header($TITLE);
do_edit_lots_of_hairy_logic();
print_standard_footer();
/dingbat/new-thing.php
include "common.php"
print_standard_header($TITLE);
who_knows();
print_standard_footer();
/dingbat/index.php
include "common.php"
print_standard_header($TITLE);
print_form();
print_standard_footer();
There are a ton of benefits to doing this:
It's less code to write than implementing your own Front Controller.
It's less code for the PHP runtime to execute than a single page, and therefore faster.
It scales out to an arbitrary number of possible modes (limited only by your filesystem).
It is recursive (imagine /dingbat/edit/easy.php vs /dingbat/edit/expert.php, with a private /dingbat/edit/common.php for shared functionality).
It keeps individual files smaller and therefore easier to "master" by developers.
It automatically makes URLs more discoverable to both users and search engines (instead of /dingbat.php?mode=edit&a=1&b=2 you have /dingbat/edit.php?a=1&b=2 - the "variables" are obvious).
If your page is public, it improves SEO and proxy behavior (URL path is far more important than the querystring). ModRewrite can work around SEO issues, but with this scheme it's simply unnecessary.
The downsides?
You have to change existing URLs (consider replacing the existing /dingbat.php with a page that redirects).
The common.php files may seem unnatural at first, because it is mostly "page-local logic". This will go away over time.
If the common logic overwhelms the individual page content, then there isn't very much benefit.
Other users have mentioned the MVC pattern, which works in concert with this file-based architecture.
This isn't really an answer, because the question is PHP, but I'm considering converting the whole code base to Rails. I know PHP has MVC frameworks like Cake, but it seems as if RoR has MVC built into it - enforced. Now, how long is it gonna take me to do this when I just wanted to add an edit function?
Related
The benefits of breaking code into very small components which do one and only one simple function are obvious. But there is nothing which mandates that we should make each and every function a separate function in itself.
Consider the following case:
There is one big function, however EACH of the cases included in the function is isolated, and runs only by itself. All of the case blocks can be just copy/pasted into a different code body, wrapped in their function name. So its modular. There wont be any multiple cases(ifs) combined, ever.
All the small functions which reside in the case blocks use $vars array as their main variable. So any number of variables in any format can be passed to the parent iterator as part of an array. There are no limitations.
The parent iterator can be run anywhere, from any place, even within itself by requesting a particular action. ie $this->run_actions('close_ticket');
It has massive advantage regarding the common procedures which need to be run, and may need to be run over all actions requested. output buffering is one, and any action hooks, filters or any other all encompassing system that can be imagined.
This format allows any future new procedures which need be run before and after any action and/or on the inputs and outputs of any action, to be easily integrated. (For the particular case i have in my hands, the appearance of such cases in future is certain!!!.) If all these actions were divided into small functions instead, you would need to either go and change hooks and filters on each of the functions, or still have some sort of other function to dispatch these onto those small functions. With this format, you just place them before or after the switch/case block.
Code reading is simple: When you see a particular case, you know what it does -> 'view_tickets' is the ticket view action, and it takes $vars as an input.
Obviously, a truly hypermassive function will have various disadvantages.
So, the question is:
Assuming that the size of the function is kept at a reasonable size and the principles of modularity and one simple action per case is preserved, also considering that anyone who works with this code in future will not need to look into this code and must not modify this code and need to know only the hooks and filters which will be documented elsewhere than code itself, (including any variables they use) do you think this could be an efficient approach to combining tasks which need common procedures run on them?
public function run_actions($action,$vars=false)
{
// Global, common filters and procedures which all actions need or may need
ob_start();
switch($action)
{
case 'view_tickets':
{
// Do things
// Echo things if necessary
break;
}
case 'close_ticket':
{
// Do things
// Echo things if necessary
break;
}
case 'do_even_more_stuff':
{
// Do things
// Echo things if necessary
break;
}
// Many more cases as needed
}
// Even more common post-processing actions, filters and other stuff any action may need
$output=ob_get_clean();
return $output;
}
You can replace conditional with polymorphism. Create an abstract action class with a method like "execute" and then subclass for all various actions implementing that method.
e.g.
function run_actions(IAction action) {
//...
action->execute();
//...
}
That way, if you will need to introduce additional behavior, you won't need to modify and test long run_actions with numerous responsibilities.
Various disadvantages:
The switch cases all use $vars so they don't have a specific signature.
This hides the signature from the developer that its thus forced to read the code.
you can't do type-hinting on $vars (force parameters to be arrays, instance of some class, etc)
no IDE autocompletion
Easier to do a mistake
forget a break and you're done. No recognizable error.
Difficult to refactor
what would you do if you need to extract the code to a function? You need to duplicate preprocessing (ob_start, etc) or to change everything
what would you do if you needed to run on action with no preprocessing?
I agree it is very simple, but it has long-run disadvantages. Up to you to strike the right balance :)
When I look at this kind of architecture, I see it as beginning to build a new programming language on top of the existing one. This isn't always a bad thing, if the features you're building are a better abstraction than the language you're building them with, but it's worth challenging what those features are.
In this case, the part of the language you're reinventing is function dispatch: you have a named action, which takes arbitrary parameters, and runs arbitrary code. PHP already does this, and quite efficiently; it also has features your system lacks, such as built-in checks of the number and (to some extent) type of parameters. Furthermore, by inventing a non-standard "syntax", existing tools will not work as well - they won't recognise the actions as self-documenting structures, for instance.
The main part you gain is the ability to add pre- and post-processing around the actions. If there were no other way to achieve this, the tradeoff might be worthwhile, but luckily you have better options, e.g. putting each action into a function, and passing it as a callback to the wrapper function; or making each action an object, and using inheritance or composition to attach the pre- and post-processing without repeating it.
By wrapping the arguments in an array, you can also emulate named parameters, which PHP lacks. This can be a good idea if a function takes many parameters, some of them perhaps optional, but it does come with the drawbacks of reinventing processing that the language would normally do for you, such as applying the correct defaults, complaining on missing mandatory items, etc
There is a simple principle that says don't use more than 2 tab indentation.
eg :
public function applyRules($rules){
if($rules){
foreach($rules as $rule){
//apply ryle
}
}
}
Becomes better when you refactor it :
public function applyRules($rules){
if($rules){
$this->executeRules($rules);
}
}
private function executeRules($rules){
foreach($rules as $rule){
$rule->execute();
}
}
And this way your code will be refactored better and you could apply more unit tests than you could.
Another rule says don't use else, instead break the code eg :
public function usernameExists($username){
if($username){
return true;
}else{
return false;
}
}
Instead of doing this, you should do this :
public function usernameExists($username){
if($username){
return true;
}
return false;
}
Only this way you ensure that your code flows 100%
In this question about including all the classes in a directory for an interpreter that needs all of them, it was suggested that a better way to handle the problem would be to conditionally include only the Command file that is needed for this iteration of the interpreter. For example, instead of this:
require_once('CommandA.php');
require_once('CommandB.php');
require_once('CommandC.php');
class Interpreter {
public function interpret($action) {
switch($action) {
case 'A':
$c = new A();
$c->execute();
break;
}
}
}
Do something more like this:
class Interpreter {
public function interpret($action) {
switch($action) {
case 'A':
require_once('CommandA.php');
$c = new A();
$c->execute();
break;
}
}
}
What are the advantages and disadvantages of going with the second choice -- dynamically and conditionally loading only the needed command -- as opposed to the first one -- including all of the files at the head of the file, C-style?
In the answer given to my previous question, speed, footprint and ease of writing were listed as advantages of conditionally loading. In other questions where this is addressed, I've seen it suggested that c-style loading is more readable and maintainable. Can anyone elaborate on these? Any other advantages or disadvantages?
The main advantage of the conditional loading is that it won't include a whole tree of php files every time you load that class. Event when you use a code cache (and you should), the files are checked for updates every time the vm encounters an /(include|require)(once)?/, so including unnecessary php files will slow down your code.
The disadvantages of this particular method is, that it is harder to maintain, and easier to make mistakes. Writing one thing twice is a code smell. Wirting My_Class means, that you need this class, and writing include "My_Class.php" also means this. This is not right.
I suggest using autoloading: http://php.net/manual/en/language.oop5.autoload.php
I just want to tell you that I am newbie to OOP and it is quite hard to me, but here is my code:
class functions
{
function safe_query($string)
{
$string = mysql_escape_string(htmlspecialchars($string));
return $string;
}
}
class info
{
public $text;
function infos($value)
{
echo functions::safe_query($value);
}
}
Is there any way to make this sentence : echo functions::safe_query($value); prettier? I can use extends, than I could write echo $this->safe_query($value);, but is it a best way? Thank you.
edit: and maybe I even can to not use class functions and just make separate file of functions and include that?
Yes, just define your function outside of a class definition.
function safe_query($string){
return mysql_escape_string(htmlspecialchars($string));
}
Then call it like this
safe_query($string);
Using a functional class is perfectly fine, but it may not the best way to design your application.
For instance, you might have a generic 'string' or 'data' class with static methods like this (implementation missing, obviously):
class strfunc{
public static function truncate($string, $chars);
public static function find_prefix($array);
public static function strip_prefix($string);
public static function to_slug($string); #strtolower + preg_replace
etc.
}
The point of a class like this is to provide you with a collection of generic, algorithmic solutions that you will reuse in different parts of your application. Declaring methods like these as static obviates their functional nature, and means they aren't attached to any particular set of data.
On the other hand, some behaviors, like escaping data for a query, are more specific to a particular set of data. It would probably be more appropriate to write something like this, in that case:
class db_wrapper{
public function __construct($params); #connect to db
public function escape($string);
public function query($sql);
public function get_results();
}
In this case, you can see that all of the methods are related to a database object. You might later use this object as part of another object that needs to access the database.
The essence of OOP is to keep both the data and its relevant behavior (methods) in one place, called an object. Having behavior and data in the same place makes it easier to control data by making sure that the behavior attached to the data is the only behavior allowed to change it (this is called encapsulation).
Further, having the data and behavior in one place means that you can easily pass that object (data and behavior) around to different parts of your application, increasing code reuse. This takes the form of composition and inheritance.
If you're interested in a book, The Object-Oriented Thought Process makes for a decent read. Or you can check out the free Building Skills in Object-Oriented Design from SO's S.Lott. (Tip: PHP syntax is more similar to Java than Python.)
Functions outside a class litter the global namespace, and it's an open invitation to slide back to procedural programming. Since you're moving to the OOP mindset, functions::safe_query($value); is definitely prettier (and cleaner) than a function declared outside a class. refrain from using define() too. but having a functions class that's a mix of unrelated methods isn't the best approach either.
Is there any way to make this sentence
: echo functions::safe_query($value);
prettier?
Not really. IMO having a functions class serves no purpose, simply make it a global function (if it's not part of a more logical class, such as Database) so you can do safe_query($value); instead.
and maybe I even can to not use class
functions and just make separate file
of functions and include that?
Create files for logical blocks of code, not for what type of code it is. Don't create a file for "functions", create a file for "database related code".
Starting with OOP can be a real challenge. One of the things I did was looking at how things were done in the Zend Framework. Not only read the manual (http://www.framework.zend.com/manual/en/zend.filter.input.html, but also look at the source code. It will take some effort but it pays of.
Looking at the context of your question and the code example you posted, I would advice you to look at some basic patterns, including a simple form of MVC, and the principles they are based upon.
(Note: this is related to this question, but I think it could have been written more clearly, so I'm trying again -- my update only helped to a limited extent.)
I've inherited some code that creates a complex form with numerous sections, and lots of possible views, depending on a number of parameters. I've been working with it for a while, and finally have a chance to think about doing some re-factoring. It's currently written procedurally, with a bunch of functions that look like this:
get_section_A ($type='foo', $mode='bar', $read_only=false, $values=array()) {
if ($this->type == 'foo') {
if ($this->mode == 'bar') { }
else { }
} else { }
}
Passing around those parameters is nasty, so I've started writing a class like this:
class MyForm {
public $type; // or maybe they'd be private or
public $mode; // I'd use getters and setters
public $read_only; // let's not get distracted by that :)
public $values;
// etc.
function __constructor ($type='foo', $mode='bar', $read_only=false, $values_array=array()) {
$this->type = $type;
// etc.
}
function get_sections () {
$result = $this->get_section_A();
$result .= $this->get_section_B();
$result .= $this->get_section_C();
}
function get_section_A() {
if ($this->type == 'foo') { }
else { }
}
function get_section_B() {}
function get_section_C() {}
// etc.
}
The problem is that the procedural functions are split into a few files (for groups of sections), and if I combine them all into a single class file, I'm looking at 2500 lines, which feels unwieldy. I've thought of a few solutions:
keep living with the nasty parameters and do something else with my time :)
live with having a 2500 line file
create a separate class for each group of sections that somehow "knows" the values of those parameters
If I do #3, I've thought of two basic approaches:
pass the MyForm object in as a single parameter
create a FormSectionGroup class with static properties that get set in MyForm, then in the group files, each class would extend FormSectionGroup and automatically have access to the current values for those parameters.
1) is probably easier to set-up, and once I'm inside get_section_A() whether I say $this->type or $myForm->type isn't all that different, but it's not exactly OOP. (In fact, I could do that without really changing to an OOP approach.)
Are there other approaches? Thoughts about which is better?
I would love nothing more than to write a lengthy explanation of how to do this, but I'm feeling a bit lazy. I do however have enough energy to point you instead to Zend_Form from the zend framework. There may be some dependencies to make it work properly (Zend_View, Elements, Decorators), but once you have them, it handles that type of situations quite gracefully.
I thought of this when I posted in your previous question - this problem reeks of decorator pattern.
It's going to be no small task, though. But I think you'll have an amazing sense of satisfaction/accomplishment once you get it done.
Having done a lot of Cocoa programming recently, I tend to view things in MVC-pattern (Model-View-Controller) terms. Hence, I'd look at the form as a controller of its various sections.
Each section object should be responsible for keeping track of its status, values and whether or not it should be displayed. Or to be precise, the section_model would take care of the values (default values, validation, etc), the section_view would take care of displaying (or not) parts of the section and the section_controller would send keep track of the status of the section and report results to the form object.
The form object should instantiate the section controllers, tell them to display or hide or whatever, and get status reports. The form object, really act a controller, can then decide when the form if completely filled out. You may have a form_model object to save the collected data, or maybe you'd rather have the section_model objects take part of that. It will take a while to get a feeling for how the different objects interact but I know from experience that if you are disciplined in designing your objects (the key is: what is an object's responsibility and what is not), you will gain a better overview and your code will be easier to upgrade. Once you find that improvements start to arise naturally, you are on the right track.
If you have the time to work on doing #3, you will probably be the happiest over the long run. Personally, I don't have the time in my job to refactor to that degree very often, and so I'd probably be forced to pick #1. #2 sounds like the worst of both worlds to me. Lots of work to get code you don't like.
What are the performance, security, or "other" implications of using the following form to declare a new class instance in PHP
<?php
$class_name = 'SomeClassName';
$object = new $class_name;
?>
This is a contrived example, but I've seen this form used in Factories (OOP) to avoid having a big if/switch statement.
Problems that come immediately to mind are
You lose the ability to pass arguments into a constructor (LIES. Thanks Jeremy)
Smells like eval(), with all the security concerns it brings to the table (but not necessarily the performance concerns?)
What other implications are there, or what search engine terms other than "Rank PHP Hackery" can someone use to research this?
One of the issues with the resolving at run time is that you make it really hard for the opcode caches (like APC). Still, for now, doing something like you describe in your question is a valid way if you need a certain amount of indirection when instanciating stuff.
As long as you don't do something like
$classname = 'SomeClassName';
for ($x = 0; $x < 100000; $x++){
$object = new $classname;
}
you are probably fine :-)
(my point being: Dynamically looking up a class here and then doesn't hurt. If you do it often, it will).
Also, be sure that $classname can never be set from the outside - you'd want to have some control over what exact class you will be instantiating.
It looks you can still pass arguments to the constructor, here's my test code:
<?php
class Test {
function __construct($x) {
echo $x;
}
}
$class = 'Test';
$object = new $class('test'); // echoes "test"
?>
That is what you meant, right?
So the only other problem you mentioned and that I can think of is the security of it, but it shouldn't be too difficult to make it secure, and it's obviously a lot more secure than using eval().
I would add that you can also instanciate it with a dynamic number of parameters using :
<?php
$class = "Test";
$args = array('a', 'b');
$ref = new ReflectionClass($class);
$instance = $ref->newInstanceArgs($args);
?>
But of course you add some more overhead by doing this.
About the security issue I don't think it matters much, at least it's nothing compared to eval(). In the worst case the wrong class gets instanciated, of course this is a potential security breach but much harder to exploit, and it's easy to filter using an array of allowed classes, if you really need user input to define the class name.
There may indeed be a performance hit for having to resolve the name of the variable before looking up the class definition. But, without declaring classes dynamically you have no real way to do "dyanmic" or "meta" programming. You would not be able to write code generation programs or anything like a domain-specific language construct.
We use this convention all over the place in some of the core classes of our internal framework to make the URL to controller mappings work. I have also seen it in many commercial open source applications (I'll try and dig for an example and post it). Anyway, the point of my answer is that it seems well worth what is probably a slight performance decrease if it makes more flexible, dynamic code.
The other trade-off that I should mention, though, is that performance aside, it does make the code slightly less obvious and readable unless you are very careful with your variable names. Most code is written once, and re-read and modified many times, so readability is important.
Alan, there's nothing wrong with dynamic class initialisation. This technique is present also in Java language, where one can convert string to class using Class.forClass('classname') method. It is also quite handy to defer algorithm complexity to several classes instead of having list of if-conditions. Dynamic class names are especially well suited in situations where you want your code to remain open for extension without the need for modifications.
I myself often use different classes in conjunction with database tables. In one column I keep class name that will be used to handle the record. This gives me great power of adding new types of records and handle them in unique way without changing a single byte in existing code.
You shouldn't be concerned about the performance. It has almost no overhead and objects themselves are super fast in PHP. If you need to spawn thousands of identical objects, use Flyweight design pattern to reduce memory footprint. Especially, you should not sacrifice your time as a developer just to save milliseconds on server. Also op-code optimisers work seamlessly with this technique. Scripts compiled with Zend Optimizer did not misbehave.
So I've recently encountered this, and wanted to give my thoughts on the "other" implications of using dynamic instantiation.
For one thing func_get_args() throws a bit of a wrench into things. For example I want to create a method that acts as a constructor for a specific class (e.g. a factory method). I'd need to be able to pass along the params passed to my factory method to the constructor of the class I'm instantiating.
If you do:
public function myFactoryMethod()
{
$class = 'SomeClass'; // e.g. you'd get this from a switch statement
$obj = new $class( func_get_args() );
return $obj;
}
and then call:
$factory->myFactoryMethod('foo','bar');
You're actually passing an array as the first/only param, which is the same as new SomeClass( array( 'foo', 'bar' ) ) This is obviously not what we want.
The solution (as noted by #Seldaek) requires us to convert the array into params of a constructor:
public function myFactoryMethod()
{
$class = 'SomeClass'; // e.g. you'd get this from a switch statement
$ref = new ReflectionClass( $class );
$obj = $ref->newInstanceArgs( func_get_args() );
return $obj;
}
Note: This could not be accomplished using call_user_func_array, because you can't use this approach to instantiate new objects.
HTH!
I use dynamic instantiation in my custom framework. My application controller needs to instantiate a sub-controller based on the request, and it would be simply ridiculous to use a gigantic, ever-changing switch statement to manage the loading of those controllers. As a result, I can add controller after controller to my application without having to modify the app controller to call them. As long as my URIs adhere to the conventions of my framework, the app controller can use them without having to know anything until runtime.
I'm using this framework in a production shopping cart application right now, and the performance is quite favorable, too. That being said, I'm only using the dynamic class selection in one or two spots in the whole app. I wonder in what circumstances you would need to use it frequently, and whether or not those situations are ones that are suffering from a programmer's desire to over-abstract the application (I've been guilty of this before).
One problem is that you can't address static members like that, for instance
<?php
$className = 'ClassName';
$className::someStaticMethod(); //doesn't work
?>
#coldFlame: IIRC you can use call_user_func(array($className, 'someStaticMethod') and call_user_func_array() to pass params
class Test {
function testExt() {
print 'hello from testExt :P';
}
function test2Ext()
{
print 'hi from test2Ext :)';
}
}
$class = 'Test';
$method_1 = "testExt";
$method_2 = "test2Ext";
$object = new $class(); // echoes "test"
$object->{$method_2}(); // will print 'hi from test2Ext :)'
$object->{$method_1}(); // will print 'hello from testExt :P';
this trick works in both php4 and php5 :D enjoy..