Functional PHP (2017)

Chapter 10. PHP Frameworks and FP

Now that we've seen how functional programming can be used to solve common programming issues, it is time we apply these techniques when developing with a framework. This chapter will present various ways to do so with a few of the most common PHP frameworks.

Before we start, a little disclaimer. I am by no means an expert in each of the frameworks we will discuss here. I have worked with all of them at different levels, but this doesn't mean I know everything there is to know about them. So, it is possible I will not be presenting the latest best practices here, despite the research conducted while writing this chapter.

This being said, we won't write a lot of code in this chapter. We will mainly look at how you can interface existing functional code with the framework structure and how you can leverage the various framework features to help you write in a functional way. We will also discuss the pros and cons of each framework regarding functional programming.

In this chapter, we will have a look at the following frameworks:

· Symfony

· Laravel

· Drupal

· WordPress

I hear some of you in the background whispering that Drupal and WordPress are not frameworks but content management systems. I agree with you, but keep in mind that people are using both of them to create full-blown applications with e-commerce and other features, so they have their place here.

Also, the CodeIgniter framework is missing from the list as I have never worked with it. However, you can probably use most of the advice that will be presented here with any framework, including CodeIgniter.

As a matter of fact, most of the advice in each part is useful in a variety of contexts. This is why I strongly suggest you read the sections about each framework. This will allow me to avoid repeating myself too much.

Symfony

With the focus firmly on Dependency Injection, the Symfony framework is well suited to write functional code. Symfony developers are accustomed to declaring their controllers and services in a way that explicitly define their dependencies.

We could argue that injecting the whole container is a bit problematic. In a strict sense, the controller and service can still be pure, but obviously the cognitive burden is a bit heavier since you need to read the code to know exactly which dependency is used.

In this part, we will discuss what parts of Symfony are well suited to functional programming and where you need to be cautious. We won't be able to cover everything as Symfony is a really complete framework with a lot of components but is should suffice to get you started.

Handling the request

The original Request class is not compliant with the PSR-7 HTTP message interfaces we already spoke about. This means it is not immutable, as the specification proposes. It is, however, really easy to obtain a PSR version of the request if you are using at least version 3.0.7 of the SensioFrameworkExtraBundle framework. You only need to install the required dependencies using Composer and change your controller actions signature a bit:

composer require sensio/framework-extra-bundle

composer require symfony/psr-http-message-bridge

composer require zendframework/zend-diactoros

Your controller needs to use the new ServerRequestInterface classes instead of the more traditional Request class in its method signature:

<?php

namespace AppBundle\Controller;

use Psr\Http\Message\ServerRequestInterface;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

use Zend\Diactoros\Response;

class DefaultController extends Controller

{

public function indexAction(ServerRequestInterface $request)

{

return new Response();

}

}

If, for any reason, you need to get hold of a Request or Response instance that is compatible with Symfony's interfaces, you can use the Symfony PSR-7 Bridge.

If you correctly inject only the dependencies you need in your controllers and services, with the help of the new PSR-7-compliant HTTP messages, you are now well prepared to write functional code for your Symfony application.

Database entities

One challenge you might encounter when writing completely pure function code is database access. Usually, developers use Doctrine with Symfony and, as far as I know, Doctrine does not yet have any facilities to help with writing referentially transparent code.

Using something like an IO monad is also cumbersome in the context of a framework because, at each entry and exit point of your functions, you will have to either encapsulate the parameters or transform the results to the format expected by the framework.

We will try to see how we can mitigate this issue using various techniques. While we are at it, we will also learn how to leverage the Maybe type when using Doctrine.

Embeddables

Although not strictly related to functional programming, the idea of value objects can be used to attain some sort of immutability on your entities. It is also an idea worth exploring for its own benefits.

It is an idea we have already discussed in Chapter 2, Pure Functions, Referential Transparency, and Immutability. I will, however, take this opportunity to give a somewhat different definition taken from domain-driven design:

· Entity: something that has an identity independent from its properties.

· Value object: something that has no identity separate from its properties.

A common example is a person having an address. The person is an entity and the address is a value object. If you change the name, address, or any other property of a person, it is still the same person. However, if you change anything on the address, it becomes a totally different address.

Doctrine implements this idea under the name Embeddables. The term comes from the fact that a value object is always related to an entity, or embedded, as it has no point of existing on its own. You can find documentation on the official website at http://docs.doctrine-project.org/en/latest/tutorials/embeddables.html.

Although I doesn't recommend hijacking this feature, to implement immutability for every relations you have, I strongly urge you to think of embeddables when designing your entities and using them whenever you can. It will help you with both coding functionally and improving the quality of your data model.

Avoiding setters

If you start looking for best practices regarding the use of Doctrine and most ORMs, there is a good chance you will one day find someone proposing we avoid creating setter methods. There are usually a multitude of good arguments to do so. In our case, we will just concentrate on one of them-we want immutable entities to help us write pure functional code.

In most cases, the proposed solution to get rid of setters will be to think in terms of tasks. For example, instead of having a setState and a setPublicationDate method setter on a BlogPost class, you will have a publish method, which will in turn change those two fields.

This is great advice as it allows you to have most of the business logic inside the entity where it belongs and it avoids having the object in some weird state because not all necessary steps were taken by the developer. A traditional class with setters would be something like the following:

<?php

class BlogPost

{

private $status;

private $publicationDate;

public function setStatus(string $s)

{

$this->status = $s;

}

public function setPublicationDate(DateTime $d)

{

$this->publicationDate = $d;

}

}

It can be transformed to the following implementation:

<?php

class BlogPost2

{

private $status;

private $publicationDate;

public function publish(DateTime $d)

{

$this->status = 'published';

$this->publicationDate = $d;

}

}

As you can see, we modify the values in place, leaving us with a side-effect. We might naively think that it's enough to clone the current object in the publish method and return the new version with the modified properties to obtain an immutable version of our method; sadly, this solution does not work.

Doctrine stores which entities are managed by one of its units of work and a cloned entity is not in a managed state. We could attach the entity using some trick but then we would be in one of two situations:

· Both entities are managed, leading to possible issues with the internal coherence of metadata inside Doctrine itself

· Only the latest entity is managed, meaning our call to the publish method had the side effect of detaching the previous entity from Doctrine

The nail in the coffin is that there is currently no API available to do this from inside an entity. This is why I don't recommend pursuing immutable entities with the current Doctrine version at the time of writing (that is, version 2.5.5).

Anyway, avoiding creating setters on your entities will already be a huge step in the direction of a referentially transparent codebase. It will also help you a lot with keeping your business logic all in one place with no possibility of entities being left in an invalid state.

Why immutable entities?

Instead of a long speech, let's demonstrate this using a simple example. Doctrine uses instances of the DateTime class for anything related to dates and times. Since the DateTime class is mutable, this can lead to issues not at all easy to pinpoint:

<?php

$date = $post->getPublicationDate();

// for any reason you modify the date

$date->modify('+14 days');

var_dump($post->getPublicationDate() == $date);

// bool(true)

$entityManager->persist($post);

$entityManager->flush();

// nothing changes in the database :(

The first issue is that you have a reference to the same object stored inside the entity. This means that if, for any reason, you change it, the date will also change inside the post. This might be what you want, but there is absolutely no doubt that this is a side-effect. Especially if you return the $date variable to a potential caller. How is it supposed to know that modifying the date will lead to modifying an entity?

The second issue is more problematic. As Doctrine uses the object identity and not its value to determine whether something has changed, it will not know the date is now different and saving the post back into the database will amount to nothing.

There is a package available on GitHub (https://github.com/VasekPurchart/Doctrine-Date-Time-Immutable-Types) for this particular issue, but, any time you use mutable instances instead of embeddables or any other kind of value objects, you can run into similar problems. Do yourself a favor and use immutability whenever possible.

Symfony ParamConverter

We discussed modifying already instantiated entities and persisting them back to the database. But what about getting them in the first place? The SensioFrameworkExtraBundle framework contains a nice little annotation called @ParamConverter, which allows us to let the framework do the job and keep the side-effect of getting entities from the database outside our codebase.

Here is a small example so that you understand how to use this annotation (if you want to know more, you can read the official documentation on the Symfony website at http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html):

<?php

use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;

class PostController extends Controller

{

/**

* @Route("/blog/{id}")

* @ParamConverter("post", class="SensioBlogBundle:Post")

*/

public function showAction(Post $post)

{

// do something here

}

}

Using the information from the route alongside the defined parameters conversion, the framework is able to give you the Post instance directly or generate a 404 error if it isn't able to find it.

Using the annotation, your method does not need to perform database access anymore as it will receive the data directly. We might argue that impure code exists somewhere else and it would be true, but Symfony is not supposed to be a pure codebase anyway. We were able to push the impurity out of our own code and that is what matters to us.

In this particular case, the type-hint would have been sufficient in relation to the route. The ParamConverter annotation will automatically enter an action when a function signature references an entity class. There is no harm in keeping the annotation if you find it clearer, or you can decide to only use it in more complex cases.

There will obviously be circumstances where this mechanism is not powerful enough. I know some bundles provide similar features with more flexibility; you might be able to find one that suits your needs. And if nothing else works, you can still perform the query yourself or use an IO monad to do it for you.

Maybe there is an entity

Doctrine can be quite easily adapted to return instances of the Collection and Maybe monads. The first step is to create a new repository:

<?php

use Widmogrod\Monad\Maybe as m;

use Widmogrod\Monad\Collection;

class FunctionalEntityRepository extends EntityRepository

{

public function find($id, $lockMode = null, $lockVersion = null)

{

return m\maybeNull(parent::find($id, $lockMode, $lockVersion));

}

public function findOneBy(array $criteria, array $orderBy = null)

{

return m\maybeNull(parent::findOneBy($criteria, $orderBy));

}

public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)

{

return Collection::of(parent::findBy($criteria, $orderBy, $limit, $offset));

}

public function findAll()

{

return Collection::of(parent::findAll());

}

}

Then, you need to configure Symfony to use this new class as the default repository; this can be easily done by adding the following key to your YAML configuration:

doctrine:

orm:

entity_managers:

default_em:

default_repository_class: MyBundly\MyNamespace\FunctionalEntityRepository

If you aren't using Symfony, you can use the setDefaultRepositoryClassName method on a Doctrine Configuration class instance to achieve the same effect.

With everything we have discussed regarding Doctrine, you won't be able to have a purely functional code when the database is involved but you are prepared enough to reap most of the benefits.

Organizing your business logic

The official Symfony best practices contain some advice on how and where to write your business logic. We will expand upon them a bit to facilitate writing functional code.

The first advice is to avoid writing any logic in parts related to the framework itself: routing and the controllers. Those should be as straightforward as possible. It is a good idea to follow this advice because this way it doesn't matter as much if you are forced to do some database access in the controller.

I recommend you to do everything database-related inside the controller itself, so anything with side-effects is segregated there and your business logic can follow proper functional techniques.

Also, instead of using the service container, you should inject only the dependencies you need both in your controller and your services. This will greatly reduce the cognitive burden as the signature of your methods and constructors will be enough to determine the dependencies of your business logic.

I would also recommend you avoid using setter injection as calling the setter will modify the state of your service, thus breaking immutability and also leading to possible issues if the setter is called multiple times.

By taking the decision to limit your side effects to the controller, you can concentrate on writing functional code in your entities and services. This will make the entities and services easy to reason about and to test. Then, since the controller should contain no logic of its own, you can test the final parts using integration and functional tests and quickly gain confidence in your application.

Flash messages, sessions, and other APIs with side-effects

Flash messages are often used to communicate information to your users in a non-obtrusive way. The API proposed by Symfony to manage them is sadly not referentially transparent as you need to call a method on the controller that will add the message to a queue. The same is true for session data management.

This issue could be solved by integrating them somehow inside the Response object. This would, however, need to be done at the framework level. Such changes would either need to be incorporated upstream or would require a lot of maintenance.

One solution is to leverage the Writer or State monads in your services to hold that information and then persist them in the controller as we already decided to use it for side effects related to the database.

However, I don't recommend using the IO monad as it will prove complicated without some kind of support at the framework level, especially since PHP lacks a good alternative to the do notation annotation available in Haskell. It will only complicate your code without real benefits.

The Form API is another example of instances with a lot of inner state and impure methods. It is, however, declarative enough for this fact to not pose a lot of issues. The fact that you can abstract the form creation into its own class also helps a lot with being able to consider it side-effect free.

I strongly suggest you create Form types whenever you can and treat the resulting Form instances as immutable objects as much as possible.

Laravel

As we have already discussed, the collection API from Laravel is a good example of an immutable data structure with nice functional methods on top of it. The database layer returning instances of the Collection class really helps with streamlining its use.

However, the Facade pattern proposed by the framework is a no-go if you want to keep your functions pure. As soon as you use a façade, you end up using an external dependency that is not declared in your function signature.

Whatever your take on this pattern is, if you want to write referentially transparent code, you have to get rid of them. Luckily, Laravel provides helper functions for most common tasks and a way to access the container that is baking the facade. As we will see, it is thus not that difficult to use something different.

Since Laravel is also a framework based on object-oriented principles and the MVC pattern, all general advice from the Symfony sections also applies, especially the ones about decoupling the various parts and trying to segregate side effects in a unique place for each request, often the controller.

The way of achieving that may differ a bit but not too much; this is why I encourage you to read the previous section if you haven't done so already, as that advice will not be repeated here.

Database results

As already said, Laravel has a really great immutable collection implementation. All database queries returning multiple entities will return an instance of it. There's a really good book presenting in detail all the ways you can leverage its features. You can find it alongside screencasts and other tutorials on the author's website at https://adamwathan.me/refactoring-to-collections/. The collection might be immutable, but the objects in it are not. Since the Laravel ORM, Eloquent, is really different from Doctrine, it is, however, possible for us to make them so. Instead of using a Repository pattern and the UnitOfWork pattern, you simply have methods on a Model class that you have to extend, the ActiveRecord pattern. This means it is possible to implement your methods in a way that makes your entities immutable without having the issues we encountered about the internal state of Doctrine itself:

<?php

use Illuminate\Database\Eloquent\Model;

class BlogPost extends Model

{

private $status;

private $publicationDate;

public function publish(DateTime $d)

{

$new = clone $this;

$new->status = 'published';

$new->publicationDate = $d;

return $new;

}

}

As long as you don't modify the field used for the primary key, any call to the save method of your object will update the current row in the database. You might, however, want to add a __clone method on your object if you have non-scalar properties. PHP will only perform a shallow copy by default, meaning all references will stay the same. It might be what you want, but you need to make sure of it.

If you want to enforce the immutability of certain properties, there is a package available on GitHub (https://github.com/davidmpeace/immutability) to do exactly that. It should not be necessary if you are rigorous, but it might be a nice feature to have in a legacy codebase with both traditional and functional parts.

Using Maybe

As with Doctrine, it is also possible to return an instance of Maybe instead of null. As the structure is a bit different, we first need to create a new Builder class:

<?php

use Illuminate\Database\Eloquent\Builder as BaseBuilder;

use Widmogrod\Monad\Maybe as m;

class FunctionalBuilder extends BaseBuilder

{

public function first($columns = array('*'))

{

return m\maybeNull(parent::first($columns));

}

public function firstOrFail($columns = array('*'))

{

return $this->first($columns)->orElse(function() {

throw (new ModelNotFoundException)- >setModel(get_class($this->model));

});

}

public function findOrFail($id, $columns = array('*'))

{

return $this->find($id, $columns)->orElse(function() {

throw (new ModelNotFoundException)- >setModel(get_class($this->model)); });

}

public function pluck($column)

{

return $this->first([$column])->map(function($result) {

return $result->{$column};

});

}

}

Multiple methods were redefined because of the use of the first function which now returns an instance of the Maybe type instead of null. There is, however, no need to return instances of the Collection as the Laravel version is already a nice implementation even if it is not a monad.

Now we need our own Model class, which will use our FunctionalBuilder method:

{

return $this->find($id, $columns)->orElse(function() {

throw (new ModelNotFoundException)- >setModel(get_class($this->model));

});

}

public function pluck($column)

{

return $this->first([$column])->map(function($result) {

return $result->{$column};

});

}

}

Those two new classes should work in most cases, but as we are redefining methods used by the framework itself, it is possible you might run into trouble. If this is the case, I would love to hear from you so the implementation can be refined to avoid the issue.

You might also want to modify Collection monad so that an instance of the Maybe monad is returned instead of null in the various methods where it is appropriate. This will, however, require many more modifications than what we have done so far. As far as I know, there is currently no package providing this feature.

Getting rid of facades

The concept of Facades might be useful to reduce the learning curve for newcomers and it might facilitate the use of the services proposed by Laravel. But whatever your opinion of them is, they are not functional for one bit because they introduce side-causes as soon as you use them.

It is fairly easy to get rid of them by injecting the dependencies inside your controllers and services, as is common practice in the Symfony world. Besides allowing you to write functional code, there is a hidden benefit to stopping using facades-your code will be less tied to Laravel and thus you might be able to reuse it more.

Laravel offers a feature called automatic injection which will allow you to very easily get hold of the various components available through a Facade. It uses the type-hints to automatically inject the wanted dependency upon the class instantiation. It works in a multitude of contexts-controllers, event listeners, and middleware, for example.

Getting an instance of the UserRepository class is as simple as the following:

<?php

namespace App\Http\Controllers;

use App\Users\Repository as UserRepository;

class UserController extends Controller

{

protected $users;

public function __construct(UserRepository $users)

{

$this->users = $users;

}

}

The type-hint to use can be easily found by referring to the table available in the documentation at https://laravel.com/docs/5.3/facades#facade-class-reference.

This nifty mechanism doesn't really decouple you from the framework, however, as you need to use the correct type-hint. Another way to manually inject your dependencies via the bootstrap/start.php of your project is described in the article at http://programmingarehard.com/2014/01/11/stop-using-facades.html/.

HTTP request

As with Symfony, it is really easy to use the interfaces defined in PSR-7 instead of the one from the framework. Laravel uses the same bridge as Symfony to perform the transformation. You only need to install two packages using Composer:

composer require symfony/psr-http-message-bridge

composer require zendframework/zend-diactoros

And then it is enough to use the ServerRequestInterface class as the type-hint instead of Request method when you want to obtain an instance of the PSR-7 version. Laravel will take care of converting the Responsemethod to its own format itself if your controller action returns the PSR-7 version.

Closing words

The implementation decisions taken by the Laravel core developers go both ways. Some of them, such as the immutable collection implementation, are great when it comes to functional programming. Others, such as the use of Facades, make our life a bit more difficult.

It is, however, fairly simple to transform our code in order to use a more functional approach. The only difficulty you might encounter is when reading the documentation or tutorials, which will often describe patterns and practices we are trying to avoid.

All in all, Laravel is as good as Symfony when it comes to writing functional code. The book about its collection implementation mentioned earlier is also a great way to learn how to use some functional techniques in relation to the Collection monad implementation. As far as I know, this kind of resource does not exist for Symfony.

Drupal

Drupal modules until version 7 relied on hooks to perform operations. Drupal hooks are functions following a certain naming pattern that get called by Drupal when various events occur when responding to a request to modify various aspects of the generated web page.

In an ideal world, all hooks would receive all needed information to perform their work and the way to modify something would be using the return value. This is mostly true for some parts of the module API. Sadly, there are some functions that receive parameters passed by reference, such as the hook_block_list_alter function. Also, you sometimes need to access global variables, for example, to get hold of the current language.

Drupal 8 moved to a class-based approach. The content should now be created inside a controller in order to be closer to Symfony terminology. The reason is that this new version now uses some of Symfony's core components. This does not mean it is impossible to use functional programing anymore, just that things are a bit different.

It is not the role of this book to explain in detail what changed from version 7 to version 8. There are plenty of tutorials out there doing a great job of that. Most of what will be presented here is general enough to be useful and true for both Drupal versions.

Database access

In Drupal 7, there are multiple functions you can use to perform database queries and access the results. Usually, you start with a db_query function, which returns a result object with various methods to inspect and process the data. The preferred Drupal 8 way is not to get a database connection injected inside your module or service and use it in a more object-oriented way.

This change does not really affect us as, in both cases, it is not possible to query the database in a referentially transparent way. Also, people usually don't use an ORM with Drupal; most requests to the database are done using SQL directly.

This is why we won't linger on this subject besides repeating that it is important to segregate database access as much as possible so that the rest of your code can be functional.

Dealing with hooks requiring side effects

The minimal Drupal module is composed of two files, the info file and the module file. The format of the info file changed from an ad hoc text file in Drupal 7 to a YAML file in Drupal 8, but the file still contains information about the module. The module file is the main PHP file of the module.

As we saw, some hooks require side-effects to perform their job and there is hardly a way around that fact. What I can recommend is to use the module file as the one that will hold all non-strictly functional code and putting all computations somewhere else.

In the case of Drupal 8, some controller methods might also need to have side-effects. In this case, I'll give you the same advice as for Laravel and Symfony: keep those in the controller and use external services/helpers to perform referentially transparent computation.

How will we do that for the hook_block_list_alter function we spoke about earlier? First of all, this applies only for Drupal 7 as, in the next version, blocks are managed through a class, which kind of solves the issue of referential transparency for this particular case.

My advice is simply to create a second PHP file in your module, containing only pure functions. For example, this file could contain a new_blocks function taking the current blocks and language as its only parameters.

Then, in the module file, you can do the following:

function my_module_block_list_alter(&$blocks) {

global $language;

$blocks = new_blocks($blocks, $language);

}

This function clearly has both side causes and side-effects; there is not much we can do about that. However, the new_blocks function can be pure, which means you can easily reason about it and test it like we saw in the previous chapters.

This method can be applied to nearly anything. As soon as you get side causes or side-effects, perform those in the module file and then use a different file to hold your pure functions, which will do the necessary processing and computations. If you are using Drupal 8, instead of using the module file, you can use the controller as we already discussed for Symfony and Laravel.

Hook orders

The beauty of Drupal comes from all the various modules available. This is so true that some people came up with a variation of one of the Apple marketing slogans: There's a module for that!. This comes with some difficulties, however. Not all modules are equal when it comes to quality, and you usually end up with a bunch of them for any given application.

The corollary is that the information your own hooks receive may already have been altered by previous modules. Say you are writing a module to reorder some blocks on the page; it is perfectly possible that some of the blocks you expect to be present were already removed. Or maybe a key you are using in an associative array is already registered or will be overwritten.

This can lead to some issues that are a bit hard to pinpoint exactly. Since your functions will be pure, it is, however, relatively easy to detect the fact that it comes from something else by explicitly adding a test to ensure it works as expected for a given dataset.

A good piece of advice concerning this problem is to not make assumptions about what may or may not be present in anything you receive from Drupal. Always apply some kind of check to ensure that the data you receive is correctly structured and present.

Closing words

Probably for historical reasons, some Drupal hooks need to have side-effects in order to perform their duty. Also, not all information is passed as parameters to them, requiring us to access the global scope to get them. This fact requires that we find workarounds to keep as much code as possible pure.

By introducing a more object-oriented approach coupled with service injection, Drupal 8 makes things a bit easier. Quite on a par with the experience we can have with Symfony or Laravel, but things are still not perfect.

If you are rigorous in separating your impure functions from your pure ones in at least two files, your experience writing functional code can be really good. It might seem cumbersome to always create two functions to implement one hook, but it is the price you have to pay if you want pure functions and, in my opinion, it is worth it.

As we discussed, you can still experience issues on the final page rendering even if your pure code is thoroughly tested due to the order some hooks are called in, but those are usually easier to spot if you can have confidence in your functions.

The functional developer experience with Drupal is not perfect, but it gets close. You will have to make some concessions, but you can bind those to a few files to limit their impact on the rest of your code.

WordPress

WordPress also has a hook system in place, although different from Drupal's one. Instead of creating functions with a certain name, you register functions to a certain hook. Sadly, most of those hooks need to have side-effects by definition. For example, we can do this with the help of the wp_footer hook:

This hook provides no parameters. You use this hook by having your function echo output to the browser, or by having it perform background tasks. Your functions shouldn't return, and shouldn't take any parameters.

No return value, no parameters; we are forced to create a function with side-effects. This means that you will have to create wrapper functions around your code even more than what we just demonstrated with Drupal.

Luckily, WordPress also allows you to have multiple files per plugin. Thus, the recommendation is the same-put all your impure code in the main file. Get all the information you need from the global context and perform any kind of operation with side-effects there. Once you have everything you need, call your pure functions for processing and computation.

Some WordPress tutorials present object-oriented programming as the next evolution for developers when they have mastered a more procedural way of writing plugins. If you plan on using functional techniques, it does not matter. You can organize your code using only functions or you can group them in classes. I would advise you to stick to the method you are more at ease with.

Database access

There are basically two ways to access databases in a WordPress plugin. You can use the WP_Query method directly and its object-oriented interface. Or you can use helper functions such as get_posts and get_pages.

You might have heard or read somewhere that it is best to use the WP_Query function when writing your plugin using classes, and helpers when using functions. From a functional standpoint, it doesn't matter. None of them are in any way referentially transparent. You can use whichever you like best or suits your needs better.

There is nothing much to be said about database access in a WordPress codebase. The issue is the same as with the other frameworks-there is currently no way to perform them in a pure way.

This being said, the advice stays the same-try to segregate any code with side-causes and side-effects to a single file of your plugin and then delegate the computation and processing to pure functions living somewhere else.

Benefits of a functional approach

I said in the introduction of this part that it does not matter whether you use functions or objects to organize your code. This is only partially true. WordPress lacks all the injection features of frameworks such as Symfony or Laravel. This means that, if you are using objects, you will encounter difficulty in sharing instances around.

It isn't really an issue if your object is only used to hold pure methods that don't use any kind of internal state, but as we saw, it is sometimes necessary to make concessions. If you need to share an instance with such a state, your only solution is to make it available globally. The problem with such a variable is that it can be reassigned to something else, causing issues later on.

On the contrary, a function is available from anywhere and you cannot redefine it. This leads to more robust code as you limit the possibilities of side-effects.

Closing words

Drupal's first release dates back to 2000, making it the oldest tool presented here. WordPress was born in 2003. Drupal, however, has been rewritten since then, whereas the WordPress codebase was mostly extended without a full rewrite.

Why am I telling you this? Because most of the issues you encounter when trying to write functional code in WordPress will be related to its legacy codebase. The way software was written in 2000 is a bit different than the best practices we expect now.

A lot of work was done to modernize WordPress, but there is only so much you can do. Especially when the focus is not to make the framework functional-developer friendly. It is nonetheless possible to write functional code if you are willing to jump through some hoops to isolate the parts with side-effects.

WordPress being mostly based on hooks, most of the API is composed of functions. Some of them referentially transparent, others not at all. It will take you some rigor to cleanly isolate those from the rest of your code. The benefits are always the same:

· Reduced cognitive burden

· Facilitated code reuse

· Easier testing

The downside will be that your main plugin file will mostly be composed of really small functions that only serves as wrapper around the impure functions of the WordPress API and then call your referentially transparent functions.

If the name of your wrappers are close enough to their Wordpress counterpart, reading your code and navigating through it should be pretty easy for anyone having Wordpress knowledge. In the end, it is still a good idea to write as much functional code you are capable of.

Summary

As we already discussed earlier, there is no mainstream framework having a functional approach at its core. In this chapter, we tried to see how the techniques we've learned can be applied more or less successfully to some available frameworks and CMSes.

As we saw, it is always possible to use functional programming at least at some level. Sadly, depending on the framework, you will have to create non referentially transparent code at some point.

As I said in the introduction, I am not an expert in all the libraries we discussed in this chapter, so take everything with a grain of salt. A more seasoned developer might do things differently. The examples provide, however, a good starting point for anyone wanting to try functional programming.

Also, when doing so, remember that it is first and foremost a way of thinking. It will be the way you approach the issue at hand that is the most important. If, at some point, you need to create non-pure code to accommodate an external dependencies or the framework you are using, so be it. This won't change the benefits you can get for the functional code you've written.

Now that we've seen how to use functional programming in an existing framework or a legacy codebase, the next chapter will cover designing a whole application using a paradigm known as Functional Reactive Programming or FRP.