Automate PHP with Phake – Introduction

Share this article

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!

Frequently Asked Questions about Automating PHP with Phake

How do I install Phake in my PHP project?

To install Phake in your PHP project, you need to use Composer, a tool for dependency management in PHP. You can install it by running the command composer require --dev phake/phake. This command tells Composer to add Phake as a development dependency in your project. After running this command, Composer will download Phake and its dependencies into your project.

What is the purpose of the Phakefile in a PHP project?

The Phakefile is a crucial part of a PHP project that uses Phake. It’s where you define tasks that Phake can run. These tasks can include anything from running tests to deploying your application. The Phakefile is written in PHP, and it uses Phake’s API to define tasks.

How do I define a task in a Phakefile?

To define a task in a Phakefile, you use the task function provided by Phake. This function takes two arguments: the name of the task and a closure that defines what the task does. For example, to define a task that runs PHPUnit tests, you could write the following code in your Phakefile:

task('test', function() {
exec('phpunit');
});

How do I run a task defined in a Phakefile?

To run a task defined in a Phakefile, you use the phake command followed by the name of the task. For example, to run the ‘test’ task defined in the previous question, you would run the command phake test in your terminal.

Can I define dependencies between tasks in a Phakefile?

Yes, you can define dependencies between tasks in a Phakefile. To do this, you use the dependsOn function provided by Phake. This function takes one or more task names as arguments, and it tells Phake that the current task depends on the tasks passed as arguments. For example, if you have a ‘deploy’ task that depends on a ‘test’ task, you could define this dependency like so:

task('deploy', function() {
// deployment code here
})->dependsOn('test');

How do I use Phake to mock objects in my tests?

Phake provides a powerful and flexible API for mocking objects in your tests. To create a mock object, you use the Phake::mock function, passing the name of the class you want to mock as an argument. You can then use the Phake::when function to define how the mock object should behave when its methods are called. For example, to create a mock of a UserRepository class and define its find method, you could write the following code:

$userRepository = Phake::mock('UserRepository');
Phake::when($userRepository)->find(Phake::anyParameters())->thenReturn(new User());

How do I verify that a method was called on a mock object?

To verify that a method was called on a mock object, you use the Phake::verify function. This function takes two arguments: the mock object and a call to the method you want to verify. For example, to verify that the find method was called on the UserRepository mock from the previous question, you would write the following code:

Phake::verify($userRepository)->find(Phake::anyParameters());

Can I use Phake to stub methods on real objects?

Yes, you can use Phake to stub methods on real objects. To do this, you use the Phake::partialMock function instead of the Phake::mock function. This function creates a mock object that inherits from the real object, allowing you to stub methods while preserving the real object’s behavior for other methods.

How do I define a default task in a Phakefile?

To define a default task in a Phakefile, you use the defaultTask function provided by Phake. This function takes the name of the task that should be run when no task name is provided to the phake command. For example, to set the ‘test’ task as the default task, you would write the following code in your Phakefile:

defaultTask('test');

Can I use Phake with other testing frameworks?

Yes, you can use Phake with other testing frameworks. Phake is not tied to any specific testing framework, so you can use it with any framework that supports mocking, such as PHPUnit or Behat. To use Phake with another testing framework, you simply need to include Phake in your project using Composer and then use Phake’s API in your tests as you normally would.

Wern AnchetaWern Ancheta
View Author

Wern is a web developer from the Philippines. He loves building things for the web and sharing the things he has learned by writing in his blog. When he's not coding or learning something new, he enjoys watching anime and playing video games.

BrunoScomposerOOPHPphakePHPraketask
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week