This post primarily deals with the validation of business rules that target individual values, such as for example: "Username must be between 3-20 characters long". Common term for this type of pure, stateless validation is input validation. Another type of business rules are those that define whether the value is acceptable in the broader context in which it is used. "Username must be unique" is an example of such a business rule, but their validation is not the focus of this post.
You have probably encountered this question many times, but the choice should not even be questioned. You should do both. These two types of validation are by no means in conflict or exclusive, they are complementary.
It is understood that validation in server code is mandatory, because we should never trust UI. Attackers can easily bypass JavaScript or the entire UI and submit malicious data to the server.
But the client-side validation is equally important and useful. Not only is it a great convenience for users because it saves them time by giving instant feedback for the data entered, client-side validation avoids unnecessary round trips to the server by preventing users from sending invalid data at all.
Many proponents of the idea of server side–only validation use DRY (Don't Repeat Yourself principle) as the main argument. That may be good reasoning, but only if some important considerations are kept in mind.
The browser is just one of the interfaces or ports through which your system can be used. In terms of validating input, the same rules must apply and exist in those cases as well. For example, the registration form on the website can be one of the ways to create users, in addition to API, or a command-line and other types of tools for creating and importing users.
In the web context, form validation is often considered to be the ultimate validation, on both ends. But form is a UI concern, therefore form validation should not be regarded as server-side validation at all. Also, forms are a feature of the CRUD–style user interface, while modern web and mobile UIs have been trending towards the direction of being task based, allowing user to perform certain action, for example "Mark Todo as Done", "Set a Reminder", "Approve Friend Request", and similar. Forms are not really as common interface elements as they seem.
Most importantly, domain models are typically much more complex and rather different than view models so trying to bind a form directly to the domain model seems irrational.
Some people will find this difficult to hear, but unless you are building traditional server side rendered application, components such as Symfony or Laminas (previously Zend) Form have no place on the back-end, especially not for validation purposes.
So how do we validate input on the server side?
The systems we build can have complex business logic, hence we usually resort to domain modeling in order to abstract and organize that complexity by creating a web of interconnected objects where each object represents some meaningful unit. But along the way, we somehow forget to appropriately model simple values that have special meaning, such as email address, username, money, address, and similar. Consequently, logic for validating these values is typically scattered and duplicated throughout the code base, wherever such value is dealt with.
This phenomenon has inspired some critics to characterize it as a code smell called Primitive Obsession. Although I justify this criticism, I think the formulation itself is too harsh. We are not obsessed with primitives, we simply neglect the use of objects by taking shortcuts that are available.
Just because we can represent a certain concept as a primitive type, does not mean that we always should. Email address is not a string. Its textual representation is stringy and can be casted to a string, but it is a well-defined structure made up of a mailbox name, an @ symbol and a case-insensitive domain. Username is not a string neither, it isn't any text, but is usually defined by business rules for length and allowed characters. All these concepts have some new, special meaning, therefore they should be modeled accordingly.
Instead of representing some piece of domain knowledge as primitive type, make it a custom type, or in Domain-Driven Design (DDD) terminology, turn it into a self-validating Value Object that encapsulates all the business rules in a single place.
Here's how the definition of a Username
value object might look like:
final class Username
{
private string $username;
private function __construct(string $username)
{
if (!preg_match('/^[a-z0-9_-]{3,20}$/', $username)) {
throw new \InvalidArgumentException('Username must be alphanumeric string that may include "_" and "–", having a length of 3 to 20 characters');
}
$this->username = $username;
}
public static function fromString(string $username): self
{
return new self($username);
}
public function toString(): string
{
return $this->username;
}
}
Validation happens at the construction time through the use of guard clauses that immediately raise an exception if the passed value is not valid according to one or more criteria. This was in a way an answer to the question of where validation should live.
Self-validation, but also another important characteristic of value objects – immutability, are a guarantee that a value object is valid for the entire time of its existence. We no longer have to worry about whether we need to validate a parameter or it has already been validated, and if not, what is the best place to validate without causing duplication.
In terms of effort and time required, creating value objects for all primitive types may seem like over-engineering. But don't forget that with a primitive string, you still need to write validation logic and apply it consistently to all necessary places in the code.
When they hear the word "assert" or "assertion", most developers think of testing, specifically the operation represented in xUnit testing frameworks such as PHPUnit. However, the same term exists in the context of validation, where assertions are a more convenient way to implement guard clauses for input validation, by writing expressive statements instead of if/throw
structures.
The PHP ecosystem is known for having multiple libraries to solve the same problem. This is also the case with assertions as there are two libraries for which I know:
The second one seems to have been born in response to some shortcomings of the original library, but I personally favor Beberlei's Assert and I think it's quite solid.
Here is a refined version of the Username
constructor:
final class Username
{
private function __construct(string $username)
{
Assertion::regex($username, '/^[a-z0-9_-]{3,20}$/', 'Username must be alphanumeric string that may include "_" and "–", having a length of 3 to 20 characters');
$this->username = $username;
}
}
The example of the Username value object validation may not be demonstrative enough because it only has one guard clause, yet it is obvious that the main benefit of using assertions is that they significantly reduce the amount of code needed for implementing input validation in your models. Also, the list of built-in assertions is huge, and it is possible to extend it as well.
Although assertions are pure, stateless, general-purpose functions, I prefer to create my own Assertion class for these reasons:
Beberlei's Assert gives me that ability, where I can also override the thrown exception:
namespace App\User;
use Assert\Assertion;
use App\User\Exception\InvalidUserInput;
class UserAssertion extends Assertion
{
protected static $exceptionClass = InvalidUserInput::class;
}
Custom exception type:
namespace App\User\Exception;
use Assert\InvalidArgumentException;
final class InvalidUserInput extends InvalidArgumentException implements UserException
{
}
The decision whether to create a generic custom Assertion class or one per domain concept is always context-dependent and influenced by the amount of customizations you are making and the granularity of exception types you want to have.
In order to fully switch to this new approach of representing simple domain concepts, the key is to strictly adhere to the use of value objects for properties, constructor parameters, method parameters, etc. Entities are typically comprised of value objects, they are a great example of fully embracing type safety:
class User
{
protected UserId $id;
protected Username $username;
protected EmailAddress $emailAddress;
protected DateTimeImmutable $createdAt;
final protected function __construct(UserId $id, Username $username, EmailAddress $emailAddress, DateTimeImmutable $createdAt)
{
$this->id = $id;
$this->username = $username;
$this->emailAddress = $emailAddress;
$this->createdAt = $createdAt;
}
public static function new(Username $username, EmailAddress $emailAddress)
{
return new static(UserId::generate(), $username, $emailAddress, new DateTimeImmutable());
}
}
Just like in case of value objects, this design ensures that the entity will always be created in a valid state, regardless of the context and part of the system where it is used.
Despite this complete obsession with value objects, there must be a part of the code in which primitive values from the raw data submitted to the server are converted into value objects.
Commands are an ideal mechanism for abstracting use cases and the place to put the conversion logic:
class RegisterUser
{
protected Username $username;
protected EmailAddress $email;
public function __construct(array $payload)
{
UserAssertion::keysExists($payload, [
'username',
'email',
]);
$this->username = Username::fromString($payload['username']);
$this->email = EmailAddress::fromString($payload['email']);
}
public function username(): Username
{
return $this->username;
}
public function email(): EmailAddress
{
return $this->email;
}
}
You can handle this command directly in some action controller, or better yet, capture this procedure in a dedicated command handler which may also perform some additional business rule validation:
class RegisterUserHandler
{
private UserRepository $userRepository;
private UniqueUsernameChecker $uniqueUsernameChecker;
public function __construct(UserRepository $userRepository, UniqueUserEmailChecker $uniqueUsernameChecker)
{
$this->userRepository = $userRepository;
$this->uniqueUsernameChecker = $uniqueUsernameChecker;
}
public function handle(RegisterUser $command): void
{
if ($this->uniqueUsernameChecker->exists($command->username()) {
throw UsernameTaken::for($command->username());
}
$user = User::new($command->username(), $command->email());
$this->userRepository->save($user);
}
}
Command Handler can then be used different contexts, such as Web action:
class RegisterAction implements RequestHandlerInterface
{
public function handle(ServerRequestInterface $request): ResponseInterface
{
$payload = $request->getParsedBody();
$this->registerUserHandler->handle(new RegisterUser($payload));
return new JsonResponse(['success' => true]);
}
}
You are probably wondering how this domain model–level validation approach reflects on the user experience, in the case of a web application for example. Here's the twist – the end user should not even come into contact with input validation assertions, and therefore not see the assertion messages. The way to ensure this is having rich UI validation optimized for better user experience. That's why client-side validation is crucial.
If you are concerned about DRY, consider that in this case code reuse might result in coupling between back-end and front-end, which is a much greater concern than to strictly adhere to the DRY principle.
At the beginning, I pointed out that domain and view models are different, the same goes for their validation. The two may seem similar, but they have a different purpose and will change for different reasons, so it's completely fine to keep them separate.
Shift in mindset in terms of consistently modeling simple concepts using value objects has a positive impact on all layers of the system. Code becomes more concise, clear, without noisy if
checks in places where we do not expect them. Input validation is centralized within value objects, making it easier to find and change.
Guard clauses in value objects prevent invalid data from penetrating the domain layer. If someone tries to create an entity or aggregate composed of value objects anywhere in the application, type-safe contract guarantees that the resulting object will be valid. Not only are value objects self-validating, they spread this characteristic to the entire domain layer.
Validation at the domain model level is the ultimate solution for server-side validation, it has no alternative. In addition, decent UI validation is the first line of defense, so your system should include both.
]]>$startedAt = new DateTime('2019-06-30 10:00:00');
$finishedAt = $startedAt->add(new DateInterval('PT3M'));
var_dump($startedAt->format('Y-m-d H:i:s')); //2019-06-30 10:03:00 ❌
var_dump($finishedAt->format('Y-m-d H:i:s')); //2019-06-30 10:03:00 ✅
Both $startedAt
and $finishedAt
are 3 minutes forward in time, because methods such as add()
, sub()
or modify()
also change DateTime
object they were called on before returning it. In the above example, this certainly isn't the desired behaviour.
We can fix this by copying reference object before acting on it, like so:
$startedAt = new DateTime('2019-06-30 10:00:00');
$finishedAt = clone $startedAt;
$finishedAt->add(new DateInterval('PT3M'));
Every time I encounter clone
in PHP code things start to smell as it is usually about someone hacking someone else's bad code design. In this particular case it was used to avoid mutating behavior, but it makes the code ugly and introduces unnecessary noise.
Alternatively, this could be solved by converting original DateTime
instance to DateTimeImmutable
:
$startedAt = new DateTime('2019-06-30 10:00:00');
$finishedAt = DateTimeImmutable::createFromMutable($startedAt)->add(new DateInterval('PT3M'));
But why not using DateTimeImmutable
from the beginning?
Instead of manually applying defensive techniques in order to prevent unexpected mutation when passing around date/time objects, use DateTimeImmutable
that encapsulates those techniques, making your code more reliable.
$startedAt = new DateTimeImmutable('2019-06-30 10:00:00');
$finishedAt = $startedAt->add(new DateInterval('PT3M'));
var_dump($startedAt->format('Y-m-d H:i:s')); //2019-06-30 10:00:00 ✅
var_dump($finishedAt->format('Y-m-d H:i:s')); //2019-06-30 10:03:00 ✅
In most contexts, concept of a date is treated as a value, we compare dates by their values, and when we modify a date it becomes a different date. All this perfectly matches the definition of a Value Object, and one important characteristic of value objects is that they are immutable.
Immutability forces you to explicitly reassign a DateTimeImmutable
object every time you act on it, because it never modifies itself but a new copy is returned. After years of working with mutable DateTime
, and due to the fact that mutability is the default in imperative programming languages, it is hard to get rid of bad mutating habits and conform to the new coding style that enforces reassignment:
$this->expiresAt = $this->expiresAt->modify('+1 week');
Static analysis tools such as PHPStan and one of its extensions can warn us if we misuse DateTimeImmutable
by omitting assignment.
Yet this cognitive bias towards mutability is suppressed when we perform arithmetic operations on primitive values, for example: $a + 3;
. On its own, this gets perceived as an pointless statement that is clearly missing reassignment: $a = $a + 3;
or $a += 3;
. Would not it be lovely if we could use something similar in the case of value objects?
Some programming languages features a syntactic sugar called operator overloading that allows for implementing operators in user-defined types and classes, so that they behave much like the primitive data types. I would not mind if PHP steals this trick from another programming language that would allow us to write our code this way:
$this->expiresAt += '1 week';
Some people argue that performance-wise, it is better to use DateTime
when calculations are done within a single scope of execution. That is a valid point, but unless you are doing hundreds of operations, and given that references to the old DateTimeImmutable
object will be garbage collected, in most practical scenarios memory consumption should not be a concern.
Carbon is a super popular library that extends PHP's date/time API with a rich set of functionality. To be more accurate, it extends API of a mutable DateTime
class, which conflicts with the aim of this blog post.
So if you like working with Carbon, but you favor immutability, I suggest you consider Chronos. It is a standalone library that was originally based on Carbon, focusing on providing immutable date/time objects by default, but it also ships with mutable variants in case you need them.
Edit (05/07/2019): It turns out that Carbon does have an immutable date/time variant, which is a big plus on its account. Yet, the reason I gave Chronos advantage is that unlike Carbon, it encourages and promotes immutability by default, both in code and documentation, and that is a crucial factor with regard to the message of this post.
DateTimeImmutable
was first introduced back in the ancient PHP 5.5, and to my surprise many developers are discovering it only now. Use DateTimeImmutable
by default whenever possible, also bearing in mind some of the tradeoffs I've described, which I consider to be more a matter of habit and shift in mindset.
This was a true eye-opener for me, I immediately liked the idea and after adapting it a bit I started practicing it at work. Excited and full of enthusiasm, I shared my findings and opinions with the rest of the world:
Inspired by naming style promoted by Prooph (https://t.co/XRb4boWTJQ), I decided to adopt similar style for my code. In short:
— Nikola Poša (@nikolaposa) December 24, 2018
- no `get` prefix for getters in entities and value objects
- no `Exception` suffix
- no `Interface` suffix
Result: tidy, less verbose, concise code. 👌🏻 pic.twitter.com/812cCkmMOr
Later I found out that Doctrine Coding Standard project is also enforcing many of these conventions which gave me confidence that I'm going in the right direction because parts of the community have already adopted such naming style.
I feel like I only scratched the surface with my tweet that opened many questions, without detailed explanation and reasoning behind the ideas presented. This post aims to fix that.
In order to understand what is good about this approach, we first need to understand what is wrong with the conventional one. Following are several naming conventions which I formulated as naming anti-patterns for reason. They are the motivation for designing a new, better naming convention.
Let's start with the one for which there should be the least controversy. To give you better a sense of the problem, I'll make an analogy with one feature of human language - tautology:
In literary criticism and rhetoric, a tautology is a statement which repeats the same idea, using near-synonymous morphemes, words, or phrases, that is, "saying the same thing twice"
Tautologies are common in everyday language, and when unintentional, they are often considered a fault of style. Think of terms such as "round circle", "dry desert", "new innovation". Sometimes even acronyms are not spared of this: "ATM machine", "GPS system", "ISBN number".
Now consider this piece of code and read aloud the entire definition of this interface:
interface TodoRepositoryInterface
{
}
Exactly, tautology is present in programming, too. Until recently, I did not pay attention to that, I did not think about this at all. Now I realize that this imposed naming convention is as silly as using TodoClass
instead of Todo
for the name of the entity class. Here's why I believe so:
interface
in their definition, and therefore using I
as a prefix or Interface
as a suffix is a tautology that does not provide any additional value, but only blurs the actual purpose.The same arguments apply to abstract classes and traits, and respective Abstract
and Trait
prefixes/suffixes. However, since abstract classes should never be part of any public facing interface (consumers will deal with interfaces, value objects, entities), I think that Abstract
prefix is somewhat acceptable exception to the rule. Of course, you could still come up with a better name by using alternative prefix such as Base
. Yet, this should be used as a last resort, because I assure you that you can get the right name if you precisely describe purpose and scope of the abstract class. For example, PdoRepository
could be an abstract class with logic common for PDO-based repositories, while MySqlTodoRepository
could be a concrete implementation.
Something that is not so common in PHP, and I hope it never will be, is practice of using Impl
as a suffix for concrete implementations. That is even more noise, more tautology, because anything that isn't an interface is basically an implementation, so putting Impl
suffix on every name of every class is absurd to say the least.
It is quite clear that language construct prefixes and suffixes do not bring any value, and they add nothing but more stuff to type to your code.
What I'm focusing on here are classes that make up the domain, core business logic of the application - Entities, Value Objects, Exceptions, Events, and similar. Entities and Value Object are the least controversial, because we are all more or less used to choose a good name for them: User
, EmailAddress
, Todo
, TodoText
. But let's examine following Exception class that represents an exceptional condition in our domain:
namespace My\Todo\Exception;
final class CannotReopenTodoException extends \Exception
{
}
Reading it, Exception
suffix is not nearly as striking as in the case of Interface
suffix. Things start to change when you look into FQCN: \My\Todo\Exception\CannotReopenTodoException
because Exception
is already a namespace. But even if we ignore the repetition within the FQCN, CannotReopenTodoException
it is still a form of tautology, because wording and the context in which it is used (throw
, catch
, $ex
variable name) unambiguously indicate that we are dealing with an Exception:
try {
throw CannotReopenTodoException::notDone($todo);
} catch (CannotReopenTodoException $ex) {
}
It should now be clear that the suffix here is superfluous.
Event is another concept that is an indispensable part of event-driven and event-sourced architectures, and the same principle applies for them and most of the other domain elements that resides in their own namespace. The importance of the wording is even more pronounced in their case. FooEvent
does require suffix for clarification, but accurate description told in the past tense such as TodoWasMarkedAsDone
is self-evident.
Suffix removal is possible only if the class names are descriptive enough. Bad name is usually the result of a design flaw, and the inability to rename a class to something meaningful suggests that it has a poor cohesion.
Enough with tautologies. The claim that get
prefix is excessive is a bold statement, and it seems to be the one that is very hard to swallow for a lot of people who have read and discussed my tweet.
Getters and setters are the main forms of interaction with the properties of an object through its public interface. But given that Value objects are immutable, and Entities foster encapsulation, there should be no classical setter methods in any of them. In such circumstances, the getters take on the role of simple property accessors:
final class Todo
{
public function getId(): TodoId
{
}
public function getDescription(): string
{
}
public function getStatus(): Status
{
}
}
It becomes obvious that the get
prefix becomes excessive and provides no value to the consumer other than grouping all the property accessors with a common prefix.
I believe that the alternative "strip naked" naming convention for property accessor methods is a step closer to what will soon be a standard way of writing entities and value objects. Since the Typed Properties RFC has been accepted and feature will be available in PHP 7.4, and hopefully Read-only Properties RFC will go equally well, in the near future we will be able write our classes as follows:
final class Todo
{
public TodoId readonly $id;
public string readonly $description;
public Status readonly $status;
}
I regret that it took me a long time to start thinking pragmatically about naming, because now most of my projects, both private and open source, still suffer from this tautology syndrome and the majority will never be healed. But going forward, every new work and new backward incompatible versions of my libraries shall be in accordance with the naming style elaborated in this article.
Fellow #PHP developers, what are the features you would like to be added, changed or removed in 8.0?
— Nikola Poša (@nikolaposa) July 16, 2018
It had a surprisingly long reach, inspiring developers, prominent experts, community representatives to express their opinion through more than a hundred responses.
It would be a waste to leave such a valuable data in the form of a raw and fuzzy Twitter thread, so I finally found some time to turn it into something more useful. I created a spreadsheet containing a list of proposals and their number of votes:
Click here for a full, more transparent spreadsheet / chart
The list was processed as follows:
->
notation, have been omitted,The results clearly shout that PHP developers are eager for stronger object-oriented interface, multi-threading and asynchronous processing, strict typing, as well as some syntactic sugar additions following the example of other languages.
I would like to thank everyone who contributed in making this list, either by sending their own proposal or voting for the existing one. Let your PHP 8 wishes come true!
]]>In those situations, you may be tempted to inject the entire Dependency Injection Container instead, and lazy-load that resource-hungry service. I find that to be an anti-pattern, and I explained my views in a blog post written some time ago.
To come up with a better solution, ask yourself a tricky question: how would you solve this puzzle without the help of a DI container, in a situation where you would have to manually assemble application services? Such a challenge evokes creativity, forces us to approach a problem from a different angle, and eventually leads us to think about design patterns.
Proxy design pattern makes it possible to avoid coupling to the DI container so that you keep dependencies explicit, while achieving the same goal of lazy-loading an object that is expensive to instantiate. Here is an example for a proxy implemented using an anonymous class:
$notifier = new class implements NotiferInterface {
private $realNotifier;
public function notify(RecipientsCollection $recipients, Notification $notification) : void
{
$this->getRealNotifier()->notify($recipients, $notification);
}
private function getRealNotifier() : NotiferInterface
{
if (null === $this->realNotifier) {
$this->realNotifier = new MultiChannelNotifier(
'email' => new NativeMailer(),
'sms' => new TwilioSMS('token', new HttpClient()),
'push' => Pushover('token', new HttpClient()),
);
}
return $this->realNotifier;
}
};
You can inject this efficient object in any one that depends on NotiferInterface
, while complex logic for creating actual (real) notifier will be executed only when a notification is sent:
final class ArticleService
{
public function comment(string $articleId, array $commentPayload)
{
$article = $this->articleRepo->get($articleId);
$comment = Comment::fromInput($commentPayload);
$article->add($comment);
$this->articleRepo->save($article);
//service is instantiated only here!
$this->notifier->notify(
new RecipientsCollection([
$article->getAuthor(),
]),
new NewCommentNotification($comment)
);
}
}
Some DI container solutions, such as Zend Service Manager, go a step further with features that facilitate the use of different creational patterns. The one that is relevant to our story is LazyServiceFactory
, which completely eliminates the effort and hides the complexity of proxying application services. Internally, it uses ProxyManager - library that provides abstraction for generating proxy classes, so you will need to install that package before using this feature.
NotifierFactory.php
final class NotiferFactory
{
public function __invoke(ContainerInterface $container) : NotiferInterface
{
return new MultiChannelNotifier(
'email' => new NativeMailer(),
'sms' => new TwilioSMS('token', new HttpClient()),
'push' => Pushover('token', new HttpClient()),
);
}
};
ArticleServiceFactory.php
final class ArticleServiceFactory
{
public function __invoke(ContainerInterface $container) : ArticleService
{
return new ArticleService(
$container->get(ArticleRepositoryInterface::class),
$container->get(NotifierInterface::class),
);
}
};
services.php
use MyApp\NotifierFactory;
use MyApp\NotifierInterface;
use Zend\ServiceManager\Factory\InvokableFactory;
use Zend\ServiceManager\Proxy\LazyServiceFactory;
use Zend\ServiceManager\ServiceManager;
$serviceManager = new ServiceManager([
'factories' => [
ArticleService::class => ArticleServiceFactory::class,
NotifierInterface::class => NotifierFactory::class,
],
'delegators' => [
NotifierInterface::class => [
LazyServiceFactory::class,
],
],
'lazy_services' => [
'class_map' => [
NotifierInterface::class => NotifierInterface::class,
],
],
]);
return $serviceManager;
With just a few lines of configuration code, LazyServiceFactory
does all the heavy lifting, and an efficient Notifier
object gets returned behind the scenes whenever you require it from a DI Container.
Performance is a crucial feature of the applications we develop today, every millisecond and each memory byte counts, so optimizing the assembly part of our application can save valuable resources. Thereby, do not stuck with the easiest solution, think twice every time you are tempted to leak DI Container into the code. Breaking the Dependency Rule is not a valid compromise, because for every problem there is a proper solution. Tools such as Zend Service Manager facilitate the work needed even more.
]]>Testing web API clients is mostly about checking how they deal with responses received after sending requests to API endpoints, and for your unit tests, you introduce test doubles to simulate API calls instead of executing real HTTP requests.
When faced with such and similar challenges, PHP developers usually resort to mocking, facilitated either by PHPUnit or some alternative framework, and methods such as expects()
, with()
, willReturn()
and similar. But this persistent and excessive use of mocking seems very unnatural to me as if there are no alternatives, especially in the case where it is needed to simulate web service requests.
Sadly, mocking has become the predominant term in testing as if there are no other patterns for replacing production object for testing purposes. Almost as googling, like there's no other way to search content on the Internet.
— Nikola Poša (@nikolaposa) April 1, 2018
Ideally, test code should resemble usage examples from a README file, instead of being overwhelmed with impractical directives that make sense only in the testing context.
Web API clients (or SDKs) are typically built on top of some HTTP client implementation that facilitates communication with the API, which can be reduced to a direct usage of cURL functions or some more sophisticated and robust solution. Guzzle is probably the most popular HTTP client for PHP providing a simple and convenient object-oriented interface for executing HTTP requests.
For sending HTTP requests, Guzzle features handlers system, and amongst default handlers there is one called Mock Handler, designed just for the purpose of simulating different successful and error response scenarios without hitting an actual web API. With the help of it, instead of messing with mocking Guzzle and its methods that your API client is invoking during execution, you elegantly setup a response that should be returned when the Guzzle object is used by your API client:
use GuzzleHttp\Client;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\Psr7\Response;
use My\ApiClient;
use PHPUnit\Framework\TestCase;
class ApiClientTest extends TestCase
{
protected $apiClient;
protected $mockHandler;
protected function setUp()
{
$this->mockHandler = new MockHandler();
$httpClient = new Client([
'handler' => $this->mockHandler,
]);
$this->apiClient = new ApiClient($httpClient);
}
/**
* @test
*/
public function it_retrieves_students_collection()
{
$this->mockHandler->append(new Response(200, [], file_get_contents(__DIR__ . '/fixtures/products.json')));
$products = $this->apiClient->getStudents();
$this->assertCount(5, $products);
}
}
Can you imagine the overhead of using mocking methods for achieving the same goal in some more complex scenario?
The irony, of course, is that the author formulated this handy test double as MockHandler
, instead of StubHandler
, so I'm tempted to create a pull request to fix this inaccurate name because mocks are not stubs.
By default, a service created is shared, meaning that exactly the same instance will be returned whenever service is retrieved from a container. This is a desired behaviour in most of the cases. For example, application typically use a single database, so database connection service should be instantiated only once for the entire request lifecycle.
config.php
return [
'db' => [
'host' => 'localhost',
'user' => 'root',
'password' => 'secret',
'dbname' => 'app',
],
];
services.php
return [
DbConnectionInterface::class => function(ContainerInterface $container) {
$config = $container->get('Config');
return new DbConnection($config['db']);
}
];
Yet certain use cases may require services to be created conditionally during runtime, such as for example based on the value of a parameter resolved from the current request.
Imagine that your application stores data in multiple databases, and the database itself is selected based on certain criteria in your application logic. This implies that database connection service cannot be shared anymore because dbname
becomes a dynamic parameter for multiple connections that can exist during the request lifecycle.
This of course is not a difficult problem to solve, but things can go wrong if not treated properly.
From my experience, there are several pitfalls I've seen developers fall into in struggle to come up with a solution for such an requirement while still adhering to the usage of a DI container for assembling application services:
setter method - add a method to the service class that allows changing object's configuration on the fly:
public function __construct(DbConnectionInterface $dbConnection)
{
$this->dbConnection = $dbConnection;
$this->dbConnection->selectDatabase('some_database');
}
For this to work, database connection implementation had to be hacked to allow switching to a different database, and therefore made the class mutable for no good reason. This probably will not even be possible to achieve if you use some 3rd party libraries that were designed in a way that prevents changing object's state after its initial creation.
Don't sacrifice immutability of your services.
service location - have a DI container as a dependency and use it to build or locate appropriate service instance. Some DI container libraries, such as Zend Service Manager for example, extend PSR-11 interface with methods that allow creating discrete instances of objects, acting as factory methods:
public function __construct(ServiceManager $serviceManager)
{
$this->dbConnection = $serviceManager->build([
'dbname' => 'some_database',
]);
}
While this is a handy feature, passing around and having the entire DI container as a dependency causes testing difficulties and leads to a problem of hidden dependencies.
static factory - give up on using DI container and introduce a static factory for creating service instances in-place:
$dbConnection = DbConnectionFactory::create($dbConfig);
Not only that this approach results in tight coupling between the consumer code and creation details of its dependency, but also makes it very difficult to test its functionality with fake database connection objects for example.
The way I handle these cases is by introducing a special type of service - one whose responsibility is to create and manage objects. I avoid using the term "factory" here, because this factory class is also a service that should have its own factory (see?) when registered in the DI container. For this particular example, I will formulate service as a Database Connection Pool, which nicely describes its purpose. It encapsulates default database configuration and creates connection objects for the database name passed as an input parameter:
interface DbConnectionPoolInterface
{
public function get(string $dbName) : DbConnectionInterface;
}
final class DbConnectionPool implements DbConnectionPoolInterface
{
private $dbConfig;
public function __construct(array $dbConfig)
{
$this->dbConfig = $dbConfig;
}
public function get(string $dbName) : DbConnectionInterface
{
return new DbConnection(array_merge(
$this->dbConfig,
[
'dbname' => $dbName,
]
));
}
}
You register it with your favorite DI container the same way you do in case of any other service:
return [
DbConnectionPoolInterface::class => function(ContainerInterface $container) {
$config = $container->get('Config');
return new DbConnectionPool($config['db']);
}
];
... and inject / use it where needed:
public function __construct(DbConnectionPoolInterface $dbConnections)
{
$this->dbConnection = $dbConnections->get('some_database');
}
Additionally, you can apply Flyweight design pattern to minimize memory usage:
final class DbConnectionPool implements DbConnectionPoolInterface
{
private $dbConnections = [];
public function get(string $dbName) : DbConnectionInterface
{
if (!isset($this->dbConnections[$dbName]) {
$this->dbConnections[$dbName] = new DbConnection(array_merge(
$this->dbConfig,
[
'dbname' => $dbName,
]
));
}
return $this->dbConnections[$dbName];
}
}
]]>PHP Serbia is a user group I'm a member of, known for organizing big events that bring together people not only from Serbia but also from abroad. We organize meetups on a monthly basis, and finding speakers willing to talk is often a difficult job. Last year in September, fellow member - Milan Popović called me on the phone, asking if I would be able to meet the crew responsible for meetups by being a speaker at an upcoming meetup. He liked my post about exceptional behaviour, suggesting that I could turn it into a short talk. After a lot of hesitation, I accepted the challenge, and I quickly compiled a dozen of slides to fit everything into a 30 minutes slot.
The talk went smoothly, and was met with a great feedback, especially from Milan, whose immediate reaction was that the quality of my presentation is almost at the level of a conference talk.
Milan urged me to start submitting my talk to some major PHP conferences. I was unwilling again, but we eventually agreed to submit together, each his own proposals. It seems to me that Milan believed in my submission more than in his own.
Over time, I improved the title and abstract of my talk, and I eventually ended up with the catchy title of: Journey through "unhappy" path - Dealing with exceptional conditions.
Nevertheless, my proposals were ending with rejections, but I simply didn't care, because I wasn't optimistic about the acceptance of my proposal by any of the major conferences.
Just when I thought that submitting conference talks is a futile job, I received an email with the above subject. I got accepted for a PHP Central Europe Conference 2017 in Poland! The initial joy and excitement soon morphed into panic, because I needed to significantly improve my presentation and enrich it with content to fill 50 minutes slot. This is going to be my first conference talk ever, and unlike with meetup, the first talk of this kind in a language other than my native Serbian language, so I have to practice it well.
I worked hard for two months until the very conference and took my presentation to a whole new level, which in the end was actually a rewrite rather than an improvement of the initial presentation.
Milan did me a great favor, by organizing trial of my talk in his company's office, in front of a handful of people that gave me very useful feedback after the talk.
Conference organizers did their best to be good hosts, and they hosted Opening Day for speakers which included tour around Warsaw. We started from the Palace of Culture and Science and visited all the major attractions of Warsaw using cool old-fashioned bus as a means of transport. I really enjoyed it, it's good to be a speaker!
After the sunset, we headed to the conference venue - Ossa Congress & Spa hotel, located in the countryside about 50 kilometers away from Warsaw.
My talk was scheduled just after the lunch, so I had enough time during the break to connect my laptop and setup hands-free microphone. With no more than 50 people in the room few minutes before my talk I though that this is going to be easy, as a spoke in front of a slightly larger auditorium at a local user group meetup.
Suddenly, the crowd began flooding the room and the capacity of about 400 seats has become insufficient in short time. I still don't understand exactly what happened to me right then, but with every next person entering the room, I was more and more self-confident! Zero nervousness, zero jitter. Very - strange - feeling. I never experienced something like that before. Eventually, I think the attendees were more scared of me, and not the other way around.
Slide after slide, my talk went smoothly, fluently, keeping the audience's attention all the time. I was done in about 40 minutes, leaving enough time for questions.
The large audience seemed to have a positive impact on my performance. I'm really looking forward to the video recording of my talk to see who that person really was.
My first conference talk ever went better than I ever imagined it! In the end I got a round of applause that echoed hall for a few minutes. After the lecture, people came to me from all sides to congratulate me on a great performance. It felt so damn good!
Something that surprised not only me, but fellow speakers, too, was the amount of positive feedback I got at the Joind.in page of my talk. At the time of writing this I have 18 reviews, all 5-star rated.
Big thanks to PHP CE conference organizers for giving me a chance to speak at such a huge event, next to some of the most prominent experts from the PHP community, in front of a large audience eager to learn. Massive thanks to everyone who attended my talk and gave valuable feedback on it!
And of course, thank you Milan for being an optimist and making me get involved in all of this. Without your support, none of this would have happened. Also thanks to everyone who helped during the talk trial.
Even though I just stepped into the conference speaker career, I think I have a couple of useful tips to share:
I will continue to submit proposals persistently, hoping to get a chance to transfer knowledge in some new countries and even continents. Being a conference speaker is a major step forward in the career of every developer and one of the most exciting things to experience, so get out and talk.
]]>By their nature, DI Containers are also Service Locator implementations, design pattern that is the exact opposite to Dependency Injection. Because of that, DI Container is a double-edged sword which can mislead you if not used wisely, and ironically bring your code into a state in which there is no dependency injection at all.
The easiest way to comprehend what is right and what is not with regard to using DI Containers is by looking at the code we write in the form of two extremely simplified and broad categories.
Most of today's application share similar types of code ingredients. Business logic is made up of entities, repositories, services. Depending on the interfaces application exposes and patterns used for these purposes, we find middleware, action controllers and console commands. Often there is a need for writing customizations and add-ons for lower level components such as database handlers, loggers, and similar. All this belongs to the first, dominant category that I'm gonna formulate as the core.
All these classes and components do not function by themselves. At some point you need to create and connect their real instances, and run them. Configuration, factory classes, construction logic, bootstrapping scripts, and application runner itself constitute our second category - a thin layer that assembles the various components of our system and eventually runs it.
The following diagram illustrates this division:
It is understood that DI Container has its place only in the outer layer, but sometimes it still manages to reach the core. This is precisely the problem that I want to point out and raise awareness of.
Ideally, the only place in the system where you refer the DI Container is that outermost part of your application, consisting of factories, configurations and bootstrapping scripts, meaning that the core stuff must not be aware of the existence of a DI Container. This may sound too idealistic, but it's actually very feasible.
The phenomenon of a DIC's penetration into the core actually leads to the adoption of the aforementioned Service Locator design pattern. Many consider it anti-pattern for a reason. I see two major problems with doing service location within core classes, either in case of injecting service locator as a dependency, or worse, randomly pulling dependencies from a global/static service locator:
The two strongest arguments against this pattern that I find important are:
Keeping the DIC under control is all about creating a clear boundary between the core and assembly layer and strictly adhering to a continuous process of:
Having a boundary between the core and assembly code is all about separating concerns, they don't have to be separated at the filesystem level at all. That being said, there's nothing wrong with factories sitting right next to the classes for whose creation they are responsible:
src/
Framework/
Db/
DbConnectionFactory.php
DbConnectionInterface.php
DoctrineDbConnection.php
Post/
Post.php
PostRepositoryFactory.php
PostRepositoryInterface.php
SqlPostRepository.php
Typically, factory is a callable or a class implementing __invoke()
method that gets container instance as an argument:
class PostRepositoryFactory
{
public function __invoke(ContainerInterface $container) : PostRepositoryInterface
{
return new SqlPostRepository($container->get(DbConnectionInterface::class));
}
}
The vast majority of popular DI Containers for PHP complies with common PSR-11 interface, which is a good news from the standpoint of interoperability, as you will be able to easily switch to some alternative DI Container without touching factories.
Depending on the DI Container of your choice, you will either initialize it (fill it with service definitions) programmatically or via configuration. I prefer the latter approach because I find it much more convenient and easier to maintain:
config/services.global.php
return [
'di' => [
'factories' => [
MyApp\Framework\Db\DbConnectionInterface::class => MyApp\Framework\Db\DbConnectionFactory::class,
MyApp\Post\PostRepositoryInterface::class => MyApp\Post\PostRepositoryFactory::class,
],
],
];
Initializing DI Container means loading/merging configuration and feeding container with the data from a relevant configuration key, which is di
in this case. I'm gonna use Zend Service Manager as an example:
src/bootstrap.php
$config = [];
$files = glob('config/{{,*.}global,{,*.}local}.php', GLOB_BRACE);
foreach ($files as $file) {
$config = array_merge($config, include $file);
}
$config = new ArrayObject($config, ArrayObject::ARRAY_AS_PROPS);
$diContainer = new Zend\ServiceManager\ServiceManager($config['di']);
$diContainer->set('config', $config);
return $diContainer;
Everything from general purpose services (database adapter, mailer, logger, and similar), over domain services, repositories, and even application runners should be set in a DI container. That way, your application's main entry point will look as simple as:
public/index.php
/** @var \Psr\Container\ContainerInterface $container */
$container = require __DIR__ . '/../src/bootstrap.php';
$container->get(Application::class)->run();
Controllers are probably the most commonly misinterpreted elements of MVC-like PHP applications. With the arrival of new concepts and patterns, such tradition is transferred to action handlers and middleware. The most famous violation is the one for which they get the status of "fat", which is due to putting too much business logic in a class of such high level of abstraction.
With regard to the topic of this article, they are misused by making them DIC-aware. Just like any other service class, controller can have explicit dependencies required through their constructor, so in my mind there's no reason for them to be treated differently. You register them into dependency injection container just like any other service, meaning that depending on the specific DIC you use, you'll either write factories or rely on some "magic" mechanism for automatic injection of dependencies.
If you're worried that this approach might result in too many parameters in controller's constructor, that is a code smell and clear indicator that you should probably split it into few, smaller, cohesive controller classes.
As you define more and more services, especially if you follow my advice on controllers, your DI configuration can grow to the point if being bulky and difficult to maintain. Good practice of splitting big classes into smaller ones is a valid point in this case. Simply divide your single service definitions file into smaller logical units:
config/services.global.php
return [
'di' => [
'factories' => [
MyApp\Framework\Db\DbConnectionInterface::class => MyApp\Framework\Db\DbConnectionFactory::class,
MyApp\Post\PostRepositoryInterface::class => MyApp\Post\PostRepositoryFactory::class,
],
],
];
config/web.global.php
return [
'di' => [
'factories' => [
MyApp\Post\Web\SubmitPostAction::class => MyApp\Post\Web\SubmitPostActionFactory::class,
MyApp\Post\Web\ViewPostAction::class => MyApp\Post\Web\ViewPostActionFactory::class,
],
],
'templates' => [
'post' => 'resources/templates/post',
],
];
Doing so, not only that you will be able to organize services configuration more efficiently, but also other configuration option that relate to them.
If you find writing factories and registering services tiring and tedious activity, look for some Dependency Injection tool that reduces that effort, either through more efficient configuration-driven approach or some "magic" mechanism for automatic injection of dependencies based on type-hints. I don't believe in magic, and I prefer to keep things under control by having explicit service definitions. Zend Service Manager is my weapon of choice in this case, which can further simplify DI configuration through its Config Abstract Factory feature.
Dependency Injection is the crucial concept for building maintainable applications, and DI Containers facilitate this idea. If not used the right way, DIC can run wild and get out of control, so you should know how to tame it.
The key lesson is that DI Container should be used as Dependency Injection system, and not as a Service Locator system. Being consistent with this conviction means a discipline of keeping core services completely ignorant of their factories and the overall assembly/runtime process they are involved in. To me, Service Locator is an anti-pattern if used within the core code context. As we have seen, it is completely valid and inevitable to use it within factories and application runner scripts for example.
Ultimately, Dependency Injection Container is a tool, while Dependency Injection itself is a principle, and software design principles are evergreen. Let the principles dominate your code, and use the tools in an unobtrusive way.
]]>composer.json
file require
section of my projects. In case you didn't know, Monolog is a PSR-3 compliant logging library that allows you to save logs to various storage types and web services, while Zend Service Manager is a PSR-11 compliant dependency injection container and a service locator implementation that facilitates management of application dependencies.
In this post I'm gonna show you how the two can work together.
Preferred way of configuring Zend Service Manager is using an associative array containing definitions of services. Typically, this configuration lives in a file, along with other configurations of your application.
Monolog is based on a concept of creating Logger
instances, whereas each one is identified by a channel (name) and equipped with a stack of handlers. And just like a router, database handler, cache, or any other application dependency of that kind, Logger is a service that you register with the DI container and inject it into other application services.
Here's a basic example of a Logger service usage:
config.php
use Interop\Container\ContainerInterface;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\FirePHPHandler;
use Monolog\Logger;
return [
'dependencies' => [
'factories' => [
'AppLogger' => function (ContainerInterface $container) {
$logger = new Logger('app');
$logger->pushHandler(new StreamHandler(__DIR__ . '/../data/log/app.log', Logger::DEBUG));
$logger->pushHandler(new FirePHPHandler());
return $logger;
},
],
],
];
index.php
use Zend\ServiceManager\ServiceManager;
$config = require 'config.php';
$serviceManager = new ServiceManager($config['dependencies']);
$logger = $serviceManager->get('AppLogger');
$logger->info('Hello world');
While this is all that it takes to glue Monolog and Zend Service Manager together, configuration itself looks bulky and can become hard to maintain as you add more loggers. I prefer my configuration files to be light, plain PHP arrays, and keep object construction logic in separate classes. Besides a callable, Zend Service Manager also supports specifying factories as class names, so let's change our example accordingly:
config.php
return [
'dependencies' => [
'factories' => [
'AppLogger' => My\AppLoggerFactory::class,
],
],
];
AppLoggerFactory.php
namespace My;
use Interop\Container\ContainerInterface;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\FirePHPHandler;
use Monolog\Logger;
class AppLoggerFactory
{
public function __invoke(ContainerInterface $container)
{
$logger = new Logger('app');
$logger->pushHandler(new StreamHandler(__DIR__ . '/../data/log/app.log', Logger::DEBUG));
$logger->pushHandler(new FirePHPHandler());
return $logger;
}
}
index.php
use Zend\ServiceManager\ServiceManager;
$config = require 'config.php';
$serviceManager = new ServiceManager($config['dependencies']);
$logger = $serviceManager->get('AppLogger');
$logger->info('Hello world');
By solving one problem, we've introduced another one. Our code now contains something that varies between environments (development, staging, production). In this particular example it is a path to the log file (data/log/app.log
), but this includes everything that is specific for the environment on which application is running. Things like database connection parameters, credentials for external services, and as we now know logging configuration, should not be kept in code and put under version control by any cost! Note that configuration file with real values should not be versioned neither, but only as a template, usually named config.php.dist
by a convention.
Bearing all this mind, let's apply appropriate changes:
config.php
return [
'logger' => [
'app' => [
'file' => __DIR__ . '/../data/log/app.log',
],
],
'dependencies' => [
'factories' => [
'AppLogger' => My\AppLoggerFactory::class,
],
],
];
AppLoggerFactory.php
namespace My;
use Interop\Container\ContainerInterface;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\FirePHPHandler;
use Monolog\Logger;
class AppLoggerFactory
{
public function __invoke(ContainerInterface $container)
{
$config = $container->get('Config');
$logger = new Logger('app');
$logger->pushHandler(new StreamHandler($config['logger']['app']['file'], Logger::DEBUG));
$logger->pushHandler(new FirePHPHandler());
return $logger;
}
}
index.php
$config = require 'config.php';
$serviceManager = new ServiceManager($config['dependencies']);
$serviceManager->set('Config', $config);
$logger = $serviceManager->get('AppLogger');
$logger->info('Hello world');
Two things to note here:
'Config'
, which holds entire configuration array.As you add more and more loggers, therefore writing more factories, you start thinking about a generic factory that can instantiate loggers based on their array-like configuration, containing handlers, formatter and processors definitions.
Zend Service Manager facilitates such an idea in particular by featuring a concept of mapping multiple services to the same factory. This was made possible through $requestedName
that is passed as the second parameter of a factory.
To give you an idea of how a generic logger factory may look like:
namespace My;
use Interop\Container\ContainerInterface;
use Zend\ServiceManager\Exception\ServiceNotFoundException;
use Zend\ServiceManager\Factory\FactoryInterface;
final class LoggerFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$config = $container->get('Config');
$loggerConfig = $config['logger'];
if (! array_key_exists($requestedName, $loggerConfig)) {
throw new ServiceNotFoundException(sprintf(
'Configuration for "%s" is missing',
$requestedName
));
}
return $this->createLoggerFromConfig($loggerConfig[$requestedName]);
}
private function createLoggerFromConfig(array $config)
{
// ...
}
}
Configuration file becomes a lot more cleaner and readable:
return [
'logger' => [
'AppLogger' => [
'name' => 'app',
'handlers' => [
[
'name' => Monolog\Handler\StreamHandler::class,
'options' => [
'stream' => __DIR__ . '/../data/log/app.log',
'level' => Monolog\Logger::INFO,
],
],
[
'name' => Monolog\Handler\FirePHPHandler::class,
],
],
],
'NotificationsLogger' => [
'name' => 'notifications',
[
'name' => Monolog\Handler\LogglyHandler::class,
'options' => [
'token' => '123',
],
],
],
],
'dependencies' => [
'factories' => [
'AppLogger' => My\LoggerFactory::class,
'NotificationsLogger' => My\LoggerFactory::class,
],
],
];
After repeating these things through projects, I eventually wrote a generic logger factory whose essence I've omitted in the previous example, with the aim of letting you know at this point that I've made Monolog Factory - library that facilitates creation of Monolog logger objects in both generic and container-interop contexts. It works nicely with Zend Service Manager, but also any other PSR-11 compliant dependency injection container.
]]>