Automate PHP with Phake – Introduction
As developers, we often have to do repetitive tasks such as updating the database structure, seeding the database, writing CRUD code, running tests, and uploading files to a server. Wouldn’t it be great if we could automate these mundane tasks and proceed with solving the more important problems such as making our app more secure or more usable to our users?
Phake, an automation tool written for PHP, can do those tasks for you. If you’re familiar with Ruby, it’s basically a Rake clone. In this two-part series I’m going to walk you through integrating Phake into your workflow. I will walk you through the installation, some of the basics in using Phake and then finally some real-world examples.
Installation
Phake should be installed globally via Composer:
composer global require 'jaz303/phake=*'
This makes Phake accessible from any folder, and doesn’t require you to change your project’s composer.json
file.
If you don’t have access to the ‘composer’ command, install Composer globally.
Basics
To execute Phake tasks, you need to create a Phakefile. The Phakefile
contains the configuration for the tasks that you want to execute. If you’ve used Grunt before, a Phakefile
is similar to a Gruntfile
.
An important note about the Phakefile
is that it’s just a PHP file so you can just write it the same way as you do with your PHP projects.
Creating Tasks
You can create tasks by calling the task()
method. This takes up the name of the task as the first argument, and the function to execute as the last argument.
<?php
task('task_a', function(){
echo "Hi I'm task A!\n";
});
You can then execute it with the following command:
phake task_a
This will then return the following output:
Hi I'm task A!
Dependencies
If one task depends on another task, you can supply the name of that task right after the main task:
<?php
task('task_a', function(){
echo "Hi I'm task A!\n";
});
task('task_b', 'task_a', function(){
echo "Hi I'm task B! I need task A to execute first before I can do my thing!\n";
});
To execute the tasks in order you just have to call the task which has a dependency first. In this case task_b
depends on task_a
so we call it first:
phake task_b
Executing it will return the following output:
Hi I'm task A!
Hi I'm task B! I need task A to execute first before I can do my thing!
And you can keep on adding dependencies:
<?php
task('task_a', function(){
echo "I get to execute first!\n";
});
task('task_b', 'task_a', function(){
echo "Second here!\n";
});
task('task_c', 'task_b', function(){
echo "I'm the last one!\n";
});
Execute them by calling the the final task that needs to be called. In this case, it’s task_c
that we want to execute last:
phake task_c
It will then return the following output:
I get to execute first!
Second here!
I'm the last one!
Note that with this method of declaring dependencies, calling task_b
would result in task_a
being called first. If you don’t want this to happen and you still want to execute a specific task separately without executing its dependencies first then you can declare it using the following method:
task('task_a', function(){
echo "I get to execute first!\n";
});
task('task_b', function(){
echo "Second here!\n";
});
task('task_c', 'task_a', 'task_b', function(){
echo "I'm the last one!\n";
});
In the example above we are setting task_a
, and task_b
as the dependencies of task_c
. Note that the order matters here. So the task right after the main task (task_a
) will get executed first, and the one right next to it (task_b
) will be the second and then finally the main task (task_c
) is executed.
With Phake there’s another way of defining your dependencies: through the use of before or after blocks right after defining the main task. In this case our main task is to eat
so we define the tasks that we want to execute before and after it under its declaration:
task('eat', function(){
echo "Yum!";
});
before('eat', function(){
echo "Wash your hands before you eat\n";
});
after('eat', function(){
echo "Brushy brush! brush!\n";
});
When you execute eat
you get the following output:
Wash your hands before you eat
Yum!
Brushy brush! brush!
Grouping Tasks
With Phake you can also group related tasks together:
group('clean_the_house', function(){
task('polish_furniture', function(){..});
task('wash_the_clothes', function(){..});
task('mop_the_floor', function(){..});
});
Grouped tasks can be called using the group name that you specified, followed by a colon, then the name of the task that you want to execute:
phake clean_the_house:polish_furniture
If you want to execute all of the tasks in a group you can just make the final task depend on the first and second task. In the example below, the final task that we want to execute is the mop_the_floor
task so we make it depend on the polish_furniture
and wash_the_clothes
task:
group('clean_the_house', function(){
task('polish_furniture', function(){..});
task('wash_the_clothes', function(){..});
task('mop_the_floor', 'polish_furniture', 'wash_the_clothes' function(){..});
});
Then we simply call the mop_the_floor
task from the terminal:
phake clean_the_house:mop_the_floor
This will then call the tasks in the following order:
polish_furniture
wash_the_clothes
mop_the_floor
Describing Tasks
After some time of using Phake, you might accumulate a bunch of tasks in your Phakefile
, so its a good idea to have some sort of documentation. Lucky for us, Phake comes with a utility that allows us to describe what a specific Phake task does. You can use it by calling the desc
method right before the declaration of the task that you want to describe:
desc('Allows you to water the plants');
task('hose', function(){..});
desc('Allows you to wash the dish');
task('dish_washer', function(){..});
You can then list out the available tasks in your Phakefile with the following command:
phake -T
It will return an output similar to the following:
hose Allows you to water the plants
dish_washer Allows you to wash the dish
Passing Arguments to Tasks
To make the tasks more flexible we can also pass in arguments. This can be done by declaring a parameter in the function. This can then be used to access individual arguments that you pass in to the task:
task('brush_teeth', function($args){
$motion = (!empty($args['motion'])) ? $args['motion'] : 'circular';
$includes = (!empty($args['includes'])) ? $args['includes'] : '';
brush($motion, $includes);
});
Arguments can be passed by including a name-value pair right after the name of the task. If you wish to pass in more than 1 argument you can separate them by using a single space between the value of the first argument and the name of the second argument:
phake brush_teeth motion=horizontal includes=tongue,teeth,gums
If you need to pass in arguments with spaces between them you can simply wrap it up in single or double quotes:
phake brush_teeth motion="circular horizontal and vertical"
Conclusion
Now that we’ve seen what Phake is for and how we can execute tasks with it, we’ve readied the terrain for some real world applications in part two. Stay tuned!