This part two of a series looking at two different programming styles (sometimes called programming paradigms) that you can use when writing WordPress plug-ins. In part one Tom McFarlin covered object-oriented programming. In this part we'll be looking at functional programming.
Because the experience level of readers varies, we’re going to be talking about programming at a high-level, so if you’re a beginner, then you should have no problem following along. If, however, you’re a more experienced developer, then you may find more useful information later in the article.
What Is Functional Programming?
Functional programming is probably the style with which you are most familiar - and almost universally - is the style used in the various WordPress code snippet websites floating around the internet. For this reason it can sometimes be viewed as 'entry level' programming: the style employed by beginners until they've learnt to master object-oriented programming. This is incredibly misleading, because while functional programming is much simpler, it is not in itself inferior.
Functional programming emphasises the evaluation of functions, and avoids the notion of states or objects as opposed to object-oriented programming which encourages thinking about code as acting on object(s), using methods to change those objects, or interact with them. Let's look at a very simple example comparing the two styles:
// Functional method function add_two( $n ) { return $n +2; } $a = 2; $b = add_two( $a ); // $b = 4; // Object oriented method class Number { var $value = 0; function __construct( $a ) { $this->value = $a; } function add_two() { $this->value = $this->value +2; } } $a = new Number( 2 ); echo $a->value; //Prints 2 $a->add_two(); echo $a->value; //Prints 4
This very simple example illustrates the fundamental difference in style of the two paradigms: functional programming focuses on passing arguments to, and receiving values from functions. There are no 'objects' that are being acted on, only parameters and return values. Conversely, the object-oriented approach assigns an object various properties (in our case a 'value') and methods act on those properties.
Functions: The Basics
Defining functions is very simple:
function add( $number, $number2 = 1 ) { // Perform code acting on passed variables $sum = $number + $number2; // Optional, if needed you can return a value return $sum; }
Once the function is declared it can be used anywhere in your plug-in - in other words it has global scope.
$a = 4; $b = 7; echo add( $a, $b ); // Prints 11
You may have noticed that in the definition of add
, the second argument is set equal to 1
. This sets a default value for $number2
(in this case, 1), and by doing so makes the argument optional. If the argument is not supplied, the value is taken to be the default value:
echo add( 4 ); // Prints 5 echo add( 4, 1 ); // Prints 5
On the other hand, no default value is provided for the first value, so omitting that argument will throw an error
echo add(); // Throws an error as $number is not defined
You can also have a variable number of arguments. Inside the function we can use func_num_args()
to get the number of arguments received, while func_get_arg()
allows you access a particular passed variable, indexed from 0.
function sum() { // Get the number of arguments given to sum() $number_args = func_num_args(); $sum = 0; if ( ! $number_args ) return $sum; for ( $i = 0; $i < $number_args; $i++ ) { $sum += func_get_arg( $i ); } return $sum; } echo sum( 1, 2, 3, 4 ); //Prints 10 echo sum( 1, 2 ); //Prints 3 echo sum(); //Prints 0
The above can be used in object methods too. Finally, by declaring a variable as `global` you can access the variable from inside a function.
$a = 'Hello'; $b = 'World'; function hello_world() { // This is necessary to access $a and $b // declared outside of the function scope. global $a, $b; $b = $a . ' ' . $b; } hello_world(); echo $b; // Prints 'Hello World'
Why Use Functional Programming?
Deciding which programming style to use comes down to judgement - and yes - personal preference. It is not more right or wrong to use functional over object-oriented programming, but more often than not there is one style which is better suited for what you're trying to achieve.
Sometimes object oriented programming simply isn't necessary, and only over complicates matters, or introduces superfluous code. An example might be the various 'utility' functions WordPress provides. These are generic functions which serve to perform a particular purpose. For example wp_trim_words( $text, $num_words )
simply trims the given string to a certain size (in words). It wouldn't add anything to define wp_trim_words()
instead as a method belonging to some object, and would result in uglier code. With functional programming it takes one line.
One advantage of functional programming, particularly for beginners, is its simplicity. You do not have to worry about static, private or protected functions - they are all global. Neither does the notion of static variables exist. At the very basic level your function returns an output derived from what you've given it. For example, get_the_title( 7 )
will return the title for the post with ID 7.
Another advantage of functional programming is that functions are accessible globally. With object-oriented programs, in order to act on a specific object, you need to pass around that object. This can sometimes be tricky. To illustrate this let's take an example from part one:
class DemoPlugin { public function __construct() { add_action( 'wp_enqueue_scripts', array( $this, 'register_plugin_scripts' ) ); } public function register_plugin_scripts() { // Register plugin scripts } } $demo_plugin = new DemoPlugin();
When WordPress stores the register_plugin_scripts()
method so that it can be called when the wp_enqueue_scripts
action is triggered it does so by referencing not only the method, but also the object $demo_plugin
. This is because the same method for different instances of an object are considered different methods - that is, $demo_plugin->register_plugin_scripts()
and $copy_of_demo_plugin->register_plugin_scripts()
are not the same. This may seem odd - but methods can behave differently for different instances of the same class, so we need to reference both method and instance.
But why does this matter? It makes it very difficult for a third party plug-in or theme to unhook that method, since to do so they would need to call:
remove_action( 'wp_enqueue_scripts', array( $demo_plugin, 'register_plugin_scripts' ) );
But in general they won't have access to the $demo_plugin
variable. (Note: if the method is declared static, then you can get around this).
Object-Oriented and Functional Programming in WordPress
Of course object-oriented programming has its advantages, as discussed in part one. As Tom also mentioned, it is unavoidable when using WordPress' widget API. Another common example is WP_Query()
. Here an object oriented approach is clearly the best: you have an object (in this case a query), which has various properties (i.e. search criteria, pagination information, matching results) and you want to act on that query (parse it, generate and sanitise the corresponding SQL, and return the results).
WP_Query()
demonstrates how powerful object-oriented programming can be when used correctly. After initiating the query:
$the_query = new WP_Query( array(...) );
Not only can you access the results, but other information too such as, pagination values: how many pages of results there are, which page is being viewed, the total number of results, and the 'type' of query, e.g. $the_query->is_search()
, $the_query->is_single()
etc. There is also the entire 'loop' infrastructure;
if ( $the_query->have_posts() ) { echo '<ul>'; while( $the_query->have_posts() ): $the_query->the_post(); // The Loop echo '<li>' . get_the_title( $the_post->ID ) . '</li>'; endwhile; echo '</ul>'; } wp_reset_postdata();
Which hides all the internal juggling of results and globals behind a human-friendly API.
So what about get_posts()
? This just serves as a wrapper for WP_Query()
, and simply returns an array of posts matching the query. As such, you don't get the 'bells and whistles' of WP_Query()
, but it is slightly more efficient. So whether you should use get_posts()
or WP_Query()
depends on your use case (for example, whether you require pagination or not), but it's also down to personal preference.
$results = get_posts( array( ... ) ); if ( $results ) { echo '<ul>'; foreach( $results as $the_post ) { echo '<li>' . get_the_title( $the_post->ID ) . '</li>'; } echo '</ul>'; }
Summary
Hopefully these two articles have helped highlight the advantages and disadvantages of these programming styles. The take away point is that there is no right and wrong here, and each programmer will have their own personal preference. But some contexts lend themselves more readily to a certain programming style - and as such you should expect your plug-in to contain a mixture of both.
Comments