PHP Best Practices and Tips by Toptal Developers

Share

This resource contains a collection of PHP best practices and PHP tips provided by our Toptal network members.

This resource contains a collection of the best PHP practices and PHP tips provided by our Toptal network members. As such, this page will be updated on a regular basis to include additional information and cover emerging PHP techniques. This is a community driven project, so you are encouraged to contribute as well, and we are counting on your feedback.

PHP has evolved in a really quick and dirty way, almost as a consequence of being the favorite server language of the web. PHP now has all the things you look for in a robust language - it is flexible and dynamic. Although the older PHP versions weren’t good with OOP, newer versions of the languages support almost everything needed, and in a really smart way. The community behind PHP is the main reason of its success. PHP is used by 81.2% of all the websites out there that use a server side language, and lots of great frameworks were born and died trying to complete the missing pieces of the language. In the same, they guided the development of the needed parts to be done to get the best of a language whose main purpose is web development (although you can do a lot more).

Be aware, PHP is so easy to learn and implement that in inexpert hands it is really dangerous when you want to build a project that grows with time. Great PHP developers know how to use it to get the best out of this language, including which frameworks and tools to use, thus the project won’t become someone’s nighmare. Here are our tips and best practices to develop with this great language.

Check out the Toptal resource pages for additional information on PHP. There is a PHP hiring guide, PHP job description, common PHP mistakes, and PHP interview questions.

PHP Encryption Done Easily

Let’s assume you need to encrypt some data in your PHP project really quickly because the deadlines are closing in. When someone asks you to help them with encryption, your usual response would be that lousy encryption implementations could have terrible consequences. Encryption should be taken really seriously. Proper research is needed, and things are changing very fast in this delicate field. But the deadline is close, and you need to help your developer friend quickly. What we are looking for here is a good pair of common-case functions to simply encrypt and decrypt data in PHP.

Our Toptal developers came up with a solution to this problem with two custom functions that can accept parameters for sensitive information via web URL, or can be used in the back-end only. Simplicity is achieved by using the key to create the IV, which probably isn’t great for security, but is actually a good way of keeping the functions usage simple.

Here is the PHP code snippet that will do the work in question:

<?php
header('Content-Type: text/html; charset=utf-8');
/**
 * [helper fn for en/de (crypt) strings]
 * @var string
 */

$mod = ( isset( $_GET['mod'] ) ? $_GET['mod'] : '' );
$val = ( isset( $_GET['val'] ) ? $_GET['val'] : '' );

$key = 'your password for encryption';
function hideinfo( $key, $string ){	return rawurlencode( base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($key), $string, MCRYPT_MODE_CBC, md5(md5($key))))); }
function showinfo( $key, $string ){	return rawurldecode( rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, md5($key), base64_decode(rawurldecode($string)), MCRYPT_MODE_CBC, md5(md5($key))), "\0")); }

if ( $mod == 'get' && $val <> '' ){ // decode key and return it back!
	global $key;
	echo showinfo( $key, $val ) ;
	exit();
} elseif ( $mod == 'set' && $val <> '' ){ // encode key and return back val encripted!
	global $key;
	echo hideinfo( $key, $val );
	exit();
}

The full code is available also at GitHub Gist.

This code can be used in various situations. You can pass this function an array with custom data, like this:

print_r( my_array(), true );

Or it can be used for different sorts of char encodings. We hope you will find it useful and that it will help you encrypt your sensitive data quickly.

Contributors

Kresimir Pendic

Owner and web developer (MK dizajn)

Kresimir has over five years of experience developing custom modules (plugins) and themes for WordPress CMS, Magento platform, and front-end UI. He has been known to fiddle with custom JavaScript and develop for strictly front-end and mobile grounds. His communication is very good, and his level of dedication is impressive.

Get the latest developer updates from Toptal.

Subscription implies consent to our privacy policy

Using Test Driven Development in PHP with PhpUnit

In this article, we will see how using Test Driven Development (TDD, explained in deep a little later in the article) helps to write good quality code that is maintainable, reusable, and easy to debug and fix when bugs happen.

PHP and Testing

PHP and testing didn’t start together as friends. We all know that other languages are more oriented from the start to create code based on testing suites, but PHP was conceived for quick development. That’s why testing wasn’t part of the day to day routine in a PHP coder.

But times are changing, and now PHP is a mature language that can be used to build great and big applications, and using a test driven development approach is the way to go if you want to save time at the end and build good quality code.

What Is TDD?

TDD stands for Test Driven Development. Basically this means: write your test cases first, and your code later. At first, your tests will fail, because the code will be empty for that case, and that’s fine. Your mission here is making the test pass by building the code to make it happen. This allows you to focus your coding process to pass well described specs, instead of having it all in your head while coding (points in favor for when you need to work under pressure or you’re tired).

More specifically, the pattern behind TDD can be summarized by the following flow chart:

TDD flowchart

So I summarize this as:

  1. Write your test case
  2. Write code for your test code
  3. Test
  4. Fix and refactor
  5. Move to next test case

For those out there following an agile approach, this sounds very similar. Well it is, because TDD is suited for agile development.

Of course, things could go wrong, but if you found a bug later you have to write another test case, clearly missing from your suite. The good part of this is that when writing new features, they will have to also pass the current automated tests.

Unit Testing

Ok, we know what TDD means, but what about Unit testing? Unit testing means testing part of your code isolated from the rest. For that, you need to improve your code to be able to test each component alone, without any interference from other components.

This is why TDD is great for development, because it force developers to isolate the different pieces of information in well known methods that can be tested individually to pass the tests.

It’s not difficult to imagine that TDD will be difficult to implement with code that makes use of God objects, or include too many concerns in one function or method. For example, a function that process a XML file and imports data into a database. You could split that into several functions, one that process the XML, another one for getting the results mapped to the database, and another for saving and checking for errors. If you do it all in one method, then it’s hard to test if that method is doing the task right. As a general rule, each method should do just one thing, and do it right.

That’s how you can do unit testing, by creating small and well defined methods with a clear task to implement, test, and prove right or wrong.

Dependency Injection

So all this sounds great, but now when you need to create code for testing, you find out that your function depends on different classes, and those classes are instantiated into the function. What should you do? How do you know the problem is not in those classes? Should you write a test suite for every library you’re using?

Well no, although you may want to use libraries that have a test suite now, don’t you?

The solution to this is dependency injection, a pattern that implements inversion of control. All these fancy words can be explained with an example, so let’s take the following function:

class Company {
	public $members;

	public function addMember($name, $position)
	{
		$member = new Member($name, $position);
		$this->members[] = $member;
	}
}

In this case, calling the method addMember implies that a member object has to be created inside the function. So when we test that method, we have to test not only that the member has been added to the $members array, but also that the constructor works as expected. Not very unit right?

Okay, so the solution for this problem is injecting the dependency in the call of the method:

class Company {
	public $members;

	public function addMember(Member $member)
	{
		$this->members[] = $member;
	}
}

Now we only need to test if the array is adding the member. Having a valid $member instance is not our problem here. So we test that individual piece of code. That’s unit testing.

In the test case, we can mock the $member argument and pass it along. However, there are frameworks like Laravel that have solved this by creating methods to resolve dependencies on the fly, without the need to pass it in the arguments. Of course this is useful for injecting service providers more than our example above, but think on this example:

class Company {
	public function sendNotificationEmail()
	{
		//create $html to send
		$mail = new Mailer();
		$mail->send($html);
	}
}

Here you have a whole new problem with the mailer function being created inside the method. What you should do instead is this:

class Company {
	public function sendNotificationEmail(Mailer $mail)
	{
		//create $html to send
		$mail->send($html);
	}
}

With service providers auto resolving themselves, you only need to do this call:

$company = new Company;
$company->sendNotificationEmail();

And the system will do the trick. And by the way, good looking semantic code right?

Introducing PHPUnit

PHPUnit, as you can cleverly deduce by the name, is a library for creating unit tests for our code. This is already included in some frameworks, and it is by far the more commonly used library for testing in PHP.

The purpose of this article is giving tips for improving your PHP code, so I’ll not enter into details of how to use PHPUnit. For that you can go to their detailed documentation.

If you followed the article so far, you know that you should write code that is independent, and that code is called testable.

Let’s take the Company example defined above, and write a test for it. For this you will have to create a file under a folder that we configure in our phpunit.xml in the root of our project, after we install it. I recommend installing using Composer, but you can download the code and include it as you wish. So, for testing the add member function, we create the following test:

class CompanyTest extends PHPUnit_Framework_TestCase
{
	/**
	* @dataProvider memberProvider
	*/
	public function testAddMember($company, $member, $expected)
	{
		// Act
		$company->add($member);
		
		// Assert
		$this->assertEquals(count($company->members), $expected);
 	}

	public function memberProvider()
	{
		$company = new Company;

		return [
			[$company, new Member, 1],
			[$company, new Member, 2],
			[$company, new Member, 3],
		];
	}
}

In this case, we are generating the test cases with a data provider that will return some information and the expected result. In our test case, we are using the function assertEquals to test if the code is working as expected. We have a lot of assertions for us to use.

With PHPUnit we can do a lot of things: we can mock objects, databases, create data providers, create test dependencies, test exceptions, output, and a lot more. We can also test our REST APIs by doing calls to our endpoints. Check the full documentation to learn more.

Final Suggestions

My suggestion for using TDD is to do it every time you can. Most projects that you start from scratch are good for a TDD approach, because you can create them as you want.

However, projects with messy code or code that is build without considering the concepts we discussed in this article or that need to be corrected quickly to go in production are not always a good fit. What I suggest in those cases is to use TDD to refactor pieces of the code and improve the code by parts. Taking all the code and rebuilding everything is not an option in most cases.

TDD forces you to think in how to structure every function, and that’s good. With time you will find this task easier to do, and your code will be really easy to update and refactor.

Contributors

Franco Risso

Freelance PHP Developer
Germany

Franco has been working on PHP, MySQL, and JavaScript since the dark days of Internet Explorer 5. He loves REST APIs to separate consumers from providers and TDD to improve code quality. He thrives in Node.js frameworks like Express and React/Redux for the front end. He has read extensively on startups and believes in their potential to bolster economy and social progress. He is a proactive individual, constantly striving to improve his work.

Show More

How to Write Comment-Less Code?

A lot of programmers are used to adding a lot of comments to their code. They see this as a good practice, and there are some programming courses that encourage this approach.

This leads to code that has a lot of comments to each block of code, replacing what the code should say already. Toptal developers, on the other hand, recommend that code should be written to be easy to read and understand, and should express what you want to achieve.

We see in the JavaScript world several frameworks like AngularJS and ReactJS, trying to make the code as semantic as possible. Why should PHP or any backend language should be different?

Developers are sometimes under pressure to deliver fast, and it’s ok to put some comments here and there, to explain to yourself and others what you are doing there. But if you incorporate some simple rules for writing your code it will be better, and everybody that works with your code in the future will appreciate it.

To illustrate with an example, compare this code snippet:

/*
This gets all the products related with a person
*/
$res = $obj->query('SELECT ...');
while($row = $res->getNext()){
...
}

with this one:

$args = [
  ‘userId’ => $userId
];
$products = Products::getProducts($args);
foreach( $products as $product){
...
}

The second one is faster to understand and read, while the first one implies to read the comment first, and then the code, which is not good.

How can you achieve this? Here are suggestions on how to avoid code overload with unnecessary comments:

  • Code conventions: Use a common way to name variables, functions, indentation, classes, and the use of brackets among other things. Take a look at PHP Framework Interop Group to learn some of the recommended conventions, and try to remember and follow them in all your projects.
  • Clear names for variables: Always try to put names expressing what you want to do with them.
  • Keep functions short: Try to write as few lines as possible when writing functions. This doesn’t mean you should be doing functional programming, but try to put small pieces of your code that do a specific task, like getting records from a database, in a separate function.
  • Use the keywords TODO, FIXME, NOTE for your comments. Using them forces you to write comments only when something that needs to be completed or fixed is in your code.
  • Use comments at the beginning of the file: Describe what the file does, you don’t need to comment each function unless you’re writing an open API, but for internal classes try to keep descriptions only in the top of your document. The functions’ name should express what it does. If you have functions with names GetProductsByEnabledUsers() in your classes, you may need to refactor that into other classes.
  • Keep a good structure of your code: For this it is recommended to use a good framework like Laravel, CakePHP, and Kohana to keep the structure of the files following a structured approach, following a model that makes sense, like MVC. In general, if you have classes depending on other classes, try to create folders to hold those and avoid long names in the files.
  • Maintain good indentation: Choose a convention like 4 spaces or 1 tab of size 2, but always use the same, and indent well. Other languages like Python compile only if you use good indentation, many PHP developers see this as a disadvantage. I personally love that Python forces developers to keep good code.
  • Use tools to help you out: Sometimes you’re tired, and you just want to finish. Getting to the finish line quickly often make us code poorly. Try using some tools in your code editor. Toptal developers recommend SublimeText and the plugin Phpcs that force developers to follow the standard. Also it helps to learn the standard while writing your code.
  • Use your comments as refactor signs: Sometimes, when part of the functionality needs to be done really quickly, creating comments to specify desired end results can be used as a refactor signs that this part of the code should be improved later, maybe by splitting the function or by creating better names for the variables.

Well, I hope you found this interesting and useful and decide embrace code readability. Everyone using your code will be thankful if you do.

Contributors

Franco Risso

Freelance PHP Developer
Germany

Franco has been working on PHP, MySQL, and JavaScript since the dark days of Internet Explorer 5. He loves REST APIs to separate consumers from providers and TDD to improve code quality. He thrives in Node.js frameworks like Express and React/Redux for the front end. He has read extensively on startups and believes in their potential to bolster economy and social progress. He is a proactive individual, constantly striving to improve his work.

Show More

Manage Your Dependencies in PHP with Composer

What Is a Dependency?

PHP is a great language to create web projects. One of the things you will see when using PHP is that there is a library for almost anything you need.

A dependency in your project is a library or package that your code uses for performing tasks. For example, if you need to call a REST API you can use the curl library of PHP, or better yet, use the Guzzle library, that have all the things you need for creating the calls.

The Problem with Dependency Management

One common problem of using third party code is keeping it updated while time goes on. Also, there are libraries that depend on other libraries, that depends on other libraries, and so on. That is really a bad situation in a dynamic context as web development is. Not to mention which version of the library you’ll use, as sometimes you need a different version according to the context you’re in, for example, the PHP version your server has.

And there is another catch. Requiring libraries is a big pain, you have to write all the includes into the file that needs to use a given library. When removing that class, you have to clean all the includes and delete the library. And as we all know, that can almost never happen, and we end up with a big folder of deprecated libraries, and then we need to waste our time (or the time of your team) to clean all that mess.

Meet Composer, Your New Friend

Composer is here to solve all those problems for us. When I first started using Composer, I thought it was a package manager, like Yum or Apt. However as they state in their documentation, they are a dependency management and not a package manager, because the packages are not installed globally. Instead, the packages are installed under a vendor folder inside your project.

How to Manage Dependencies

I won’t go over every detail. You can find a step by step guide explained in their getting started page, but I’ll explain quickly what you need.

First you need to install Composer. I recommend to install it globally, and set it up so you have the Composer command available. Once you do that you have to create a composer.json file in the root of your project.

If you want to add a new library to your project, all you have to do is add it to that file with the version you need, which looks something like this:

{
    "require": {
        "vendor/package": "1.3.2",
        "vendor/package2": "1.*",
        "vendor/package3": "^2.0.3"
    }
}

Once you do that, next you have to run in the command line composer install and Composer will install all the needed libraries inside the vendor/ folder of your project. If you run composer update, Composer will check for new versions of the libraries and update them accordingly.

Also, Composer will install the dependencies of these libraries without any needed extra work from you.

There are a lot of commands you can use with Composer, run composer --help to list them all.

Autoload Classes

If you are already falling in love with Composer for this, you’ll definitely love it for what comes next.

Composer offers an autoload for your classes. All you have to do is add this line in top of your project require __DIR__ . '/vendor/autoload.php'; and then just call the constructor of your class. For example, if you’re using Guzzle, you just have to call:

$client = new GuzzleHttp\Client();

and it will work. If you don’t need it anymore, just delete the class and that’s it! Well, I lied, that’s not all but almost. Head to the next section to learn the final step.

Deleting Libraries

We talk about the pain that is deleting a library, because you not only have to be aware of that library but also of the dependencies of that library, and being careful enough not to delete a dependency being use by another library.

In composer this is just as simple as deleting the dependency from the composer.json file, and run composer update. Yes, it is that simple.

Meet Packagist, the Repository for Your Projects

As if you already don’t have enough with all this, there is a common repository for finding libraries for your projects that can be used easily with Composer.

Packagist is the place you go when you need a library. There you can search for libraries, and see what version you want to use, depending on your needs. Also, you can write your own packages, and include them there for others to use.

Of course, there are other ways to include packages, like directly from Github or other sources. That is out of the scope of this article, but you can find how to do this in the documentation page of Composer.

Versioning

When you go to the library website, you can see several available versions. In general, you will have one that is ready for production and one that is in development.

How the versioning numbers work? Well, they follow the semantic versioning standard, which is basically as follows:

You have 3 numbers, separated by a dot. So for example, in your composer.json file you can add something like "guzzlehttp/guzzle": "5.3.*" for requiring the Guzzle library. The first number, in this case 5, is called the major version. This number changes when big changes are made in the library. Changing this version will probably change the name of the functions, or the classes, or anything. The second number is the minor version, that is meant to be for functionality changes or additions, but having backwards compatibility with other versions. The third number is the patch number. This number is changed each time a bug is fixed, and doesn’t change the functionality of the package.

As you can notice, you can include the wildcard * for replacing that number. This means that when you run composer update, Composer will check for the latest number in that category (major, minor or patch) and update to the newer version. It is recommended to keep the last number with a wildcard only, and update the minor version according. However, if you really trust that library and you always want the latest version, you can of course make this a wildcard as well.

You can also use comparator operators to include a range. For example: "guzzlehttp/guzzle": ">=5.3,<5.4" is equivalent to "guzzlehttp/guzzle": "5.3.*", and also is equivalent to "guzzlehttp/guzzle": "~5.3" using the tilde (~) operator.

For more about versioning, go to the documentation of Composer about versioning.

Save Disk Space

As a last tip, if you use Git add the vendor folder in your ignore file. Having the Composer file is enough, because once the user downloads the project, it will just have to run a composer install command to fetch all the libraries.

Summary

In this article we explained what dependencies are, why they are important for our projects, and the problems we have when we deal with them.

After that, we explained how Composer address all those issues in a really smart way to keep your project dependencies organized.

Composer is another tool for your toolbelt that will save you a lot of time and headaches.

Contributors

Franco Risso

Freelance PHP Developer
Germany

Franco has been working on PHP, MySQL, and JavaScript since the dark days of Internet Explorer 5. He loves REST APIs to separate consumers from providers and TDD to improve code quality. He thrives in Node.js frameworks like Express and React/Redux for the front end. He has read extensively on startups and believes in their potential to bolster economy and social progress. He is a proactive individual, constantly striving to improve his work.

Show More

How to Uploads Large Chunk File Between Front-end and PHP?

File uploading itself is not complicated, especially with PHP as the backend. You simply copy the uploaded file from the temporary folder to wherever you want it to be, and then you’re done with it. However, when you want to upload a larger file in chunks, the situation becomes a bit more delicate.

So in theory, the procedure of uploading a file in chunks goes like this:

  1. Enable the chunk mode for the front-end javascript library.
  2. Set up the chunk size.
  3. Generate a UID for this file uploading action and send it as a parameter to the backend.
  4. The file gets chopped and uploaded piece by piece to the back-end PHP. For example, if there are three total chunks, three HTTP requests will be sent to the back-end.
  5. For each chunk the back-end receives, PHP checks if it is the last chunk. If it is not, it will copy the chunk file to the upload destination folder and rename it with the UID generated for this batch of upload and current chunk number, so that this chunk can be identified later and reassembled correctly with other pieces. If it is the last chunk, it will assemble all the pieces together, and we are set.

Enough theory, let’s show some code:

PHP:

// UID is used to identify chunked partial files so we can assemble them back when all chunks are finished uploading
$uid = $_REQUEST['uid'];
$filename = $_REQUEST['filename'];
if (empty($_FILES['file']['name'])) {
        	return '';
}
if (isset($_POST['_chunkNumber'])) {
        	// the file is uploaded piece by piece, chunk mode
        	$current_chunk_number = $_REQUEST['_chunkNumber'];
        	$chunk_size = $_REQUEST['_chunkSize'];
        	$total_size = $_REQUEST['_totalSize'];
        	
        	$upload_folder = base_path() . '/public/images/uploaded/';
        	$total_chunk_number = ceil($total_size / $chunk_size);
        	move_uploaded_file($_FILES['file']['tmp_name'], $upload_folder . $uid . '.part' . $current_chunk_number);
        	// the last chunk of file has been received
        	if ($current_chunk_number == ($total_chunk_number - 1)) {
                    	// reassemble the partial pieces to a whole file
                    	for ($i = 0; $i < $total_chunk_number; $i ++) {
                                	$content = file_get_contents($upload_folder . $uid . '.part' . $i);
                                	file_put_contents($upload_folder . $filename, $content, FILE_APPEND);                                     	unlink($upload_folder . $uid . '.part' . $i);
                    	}
        	}
} else {
        	// the file is uploaded as a whole, no chunk mode
        	move_uploaded_file($_FILES['file']['tmp_name'], $upload_folder . $filename);
}

JavaScript (AngularJS 1.x and ng-file-upload):

var s4 = function() {
        	return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
};
var generateUniqueID = function() {
        	return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
};
Upload.upload({
        	url: '/upload_image',_
        	// enable chunk mode and set chunk size to 500KB
        	resumeChunkSize: '500KB',
        	data: {
                    	filename: file.name,
                    	file: file,
                    	uid: generateUniqueID()
        	}
}).then(function(response) {
        	console.log('success');
}), function(response) {
        	console.log('error');
});

In this code example, we used ng-file-upload as the front-end uploading library. When you var_dump the $_REQUEST parameter in PHP, you’ll notice the parameters named _chunkSize, _totalSize and _chunkNumber. With these parameters, it’s easy to calculate how many chunks are there and if the current chunk is the last chunk or not. For other popular front-end file uploading libraries, such as Plupload; the parameter names may be different, but by printing out the $_REQUEST, it shouldn’t be hard to find the equivalents.

Contributors

Chuoxian Yang

Freelance PHP Developer
China

Chuoxian is a self-driven full-stack developer and tech company founder with nearly a decade of experience developing with forefront technologies and fulfilling client needs. He's fully capable of designing or building large-scale projects from the blueprint to launch. He possesses solid computer science theory and a deep, broad programming knowledge base. In addition, he is an excellent communicator and software architect.

Show More

Submit a tip

Submitted questions and answers are subject to review and editing, and may or may not be selected for posting, at the sole discretion of Toptal, LLC.

* All fields are required

Toptal Connects the Top 3% of Freelance Talent All Over The World.

Join the Toptal community.