The PHP Application Environment
The following is a short extract from our recent book, Jump Start PHP Environment, available for free to SitePoint Premium members. Print and ebook copies are sold in stores worldwide, or you can order them here. We hope you enjoy this extract and find it useful.
This piece will focus on the application environment. We’ll also discuss *AMP bundles such as XAMPP and why they’re a poor choice; production /development parity; and performance and debugging.
The application environment is the term used to describe the environment your application can find itself in during various stages of its life cycle: the production environment, the development environment, and the staging environment.
The word environment refers to the hardware and software around your application; that is, everything used to power it.
We’ll start with the most straightforward of environments: the production environment.
When you deploy your application―in other words, upload it to a server and make it publicly accessible for the target audience―you’re putting it in production, or in use. The production environment is your application’s final destination, your code’s purpose.
In an application’s life cycle, the production environment is the live server―a server computer that’s set up so that other people can connect to it and see your website. This live server will be configured to serve your application as efficiently as possible. All the extra files you used during development will be removed from the application via a process known as compiling or building, which is explained further on.
When in production, your site is considered to be live (or deployed) and will be accessible via its own domain; for example,
http://mysite.com. When you launch your site (put it into production mode), you have cause for celebration, because this is the final step in your application’s development process.
It is the equivalent of a chef cooking a meal in a restaurant and having it delivered to the patrons who ordered it.
In the development environment, your application is being actively developed. The development environment is the computer you as the developer are using to develop the app, including the computers of all your team members, regardless of whether they are near you or remote. It is important to note that despite covering both aspects, the development environment refers more to the state your app is in, rather than its physical location―the app is in the state of being developed.
In the development environment, you have various tools at your disposal―from IDEs (see Chapter 2) to unit testing libraries and standards fixers, compilers and builders, file watchers, and more―anything you need to achieve the job at hand.
If we compare our application to a smartphone, the assembly plant it’s being made in is the development environment. This environment contains all the necessary parts―the screen, the case, the battery, the various LEDs―and each part is individually tested before being used in the construction of a smartphone unit. This is called unit testing―ensuring each unit works.
For an example of unit testing in application development, see the section called “For Those Who Want More” at the end of this chapter.
To take the smartphone assembly analogy further, the battery being tested might require a separate charger attachment, or the screen may need to be tested using a robotic arm with synthetic fingers to ensure that the screen’s touch sensitivity works.
When you develop on your own computer, it’s impossible to visit the URL
http://mysite.com and expect to see your site; after all, your site is yet to go live―it’s not on the Internet. To get around this and see our site as if it were live, we fake the Internet by defining virtual hosts.
Put simply, a virtual host gives an instruction to the server program installed on your computer, such as: IF a user requests
http://mysite.com in the browser, run the file
mysite.php through PHP and show its output in the browser.
As you can see, this is nearly identical to the regular request flow of live sites. But what makes the browser ask our own computer’s server program for the
mysite.com domain, rather than look it up on the Internet’s name servers? The
hosts file is a special file present on every operating system. We mentioned it briefly in the section called “For Those Who Want More” in Chapter 1. It contains a list of domains and their appropriate IP addresses, so that any browser on your computer can read it and go directly to the IP address without having to talk to the DNS to check where to go. On Windows, that file is in
C:\Windows\System32\drivers\etc\hosts, and on Linux and Mac machines it’s in
/etc/hosts. If you put an IP-name pair into this file, the computer will obey it. We can even try it out right now. Have no fear―there’s nothing that can go wrong. Ready?
On Windows, enter the search field, type in “notepad” and once it appears, right-click it and select Run as Administrator. The system will then ask you for confirmation. In the window that opens, select File > Open and go to: My Computer > C: > Windows > System32 > drivers > etc. In the lower right corner of the Notepad window, you might need to select All Files so that the
hosts file shows. Double-click to open it.
On Linux/Mac machines, open Terminal by searching for it. On Linux, open the default text editor as the administrator by typing
sudo gedit into Terminal. You’ll be asked for your administrator password. On OS X, enter
sudo /Applications/TextEdit.app/Contents/MacOS/TextEdit, which will do the same task. In either of these editors, go to File -> Open and enter the directory
/etc to find the
hosts file. Double-click to open it.
Once the file is opened, note the first few lines: they’ll all start with the hash symbol (#). This indicates that they’re comments, and have no effect on the file. These serve to explain a file’s purpose to the user, and they exist in PHP as well.
Now, under all these comment lines, add the following line:
Save the file and open
http://bing.com in your browser. You’ve just successfully redirected all requests to Microsoft’s search engine Bing to Google! Of course, we don’t want to keep these changes; feel free to delete this line or put a hash symbol in front of it to turn it into a comment, and save the file. You should be able to visit
http://bing.com as normal again.
Using this method, we’ll later redirect all browser requests for
http://mysite.com (which will be our application’s example domain) to our own computer’s server. This will enable us to easily test the development version of our site without deploying it live.
The staging environment is a separate server (or several servers) containing a copy―also known as a mirror―of the production environment. The staging environment is often skipped in smaller companies or projects. It is designed to resemble the production environment as closely as possible, with matching versions of installed software, identical configuration values, and so on. Staging is for performing the final tests; for example, Facebook might redesign its front page, and before deploying it out into production for all users to see, it would deploy to its staging servers so that employees (dedicated non-programmers also known as the quality assurance team) can test everything first as if using it regularly. If everything goes well, the final deployment from staging to production happens.
Staging is beyond the scope of this book, but it’s good to know about it. In the age of virtual machines and small throw-away projects, staging can be unnecessary, only coming into play with bigger long-term web applications.
There is also maintenance mode, a term we must cover in this context. It’s a mode rather than an environment because the environment around the application doesn’t change―only the status of the application does. It’s usually just a switch on the production server telling those trying to access the website words to the effect of “Be right back, tuning up!”
When starting out in PHP development, it’s tempting to download and install packages such as XAMPP, WAMP, MAMP, or EasyPHP. The AMP in those names stands for “Apache, MySQL, and PHP.” XAMPP adds another P at the end for the Perl language. The first letter refers to the operating system: Windows, Linux, Mac OS X, or, in the case of XAMPP, cross-platform (meaning it works on any OS).
These bundles contain all the software you need to run your PHP applications quickly and easily on your computer. In one click, you can install everything you could ever need to write your very first PHP script. So, where’s the evil in this?
your computer will be polluted with unnecessary software
you’ll learn less than you would by installing manually
testing is diffficult
if you make a mistake, it’s either very difficult or impossible to return to a previous state
Let’s address these one by one.
Whenever you install software such as an *AMP stack on your computer, a chunk of your computer dies. Even if you delete the software later on, uncomfortable traces usually remain―often in the form of registry entries in Windows or file dust on Linux. In fact, this is especially apparent on Linux. While Windows and OS X applications are installed in an application folder with all related files inside it, on Linux the installation of software is like taking a shotgun to a castle built of Legos. One click and they’re everywhere.
As time goes on, you’ll install another library, another package, another tool. You’ll keep adding supplementary software as you develop your app further, perhaps add different items entirely because you’ve started working on a new project in parallel. Maybe app1 requires a PHP extension to edit images, and app2 needs a PHP extension that allows it to package code into closed source archives, so that your code is hidden from your competition. In time, you’ll have hundreds of megabytes of development software sitting on your machine, with no clue as to whether or not you still need it.
Your machine will slow down, applications will become less usable, and your development machine―the computer you’re working on―will become so different from the production server you eventually intend to deploy your application on that you’ll be unable to handle the difference gracefully. You’ll end up regularly combating bugs on a live website and annoying your visitors to no end.
By depending on these prebuilt packages, you also rob yourself of the experience of learning system administration work (ops, in short). Ops is, in larger companies, a team or person in charge of server issues―whether it be fixing bugs, installation of new software, upgrading existing software, and so on. In smaller teams or when working solo for clients, basic system administration is an essential skill to have.
While being able to install everything you need onto your computer with a single click is neat, there’s no user interface on a server and thus nothing to click; you need to master the commands required to set up a server’s software so that it can run your PHP application. Otherwise, you’re either destined to hire a server administrator to help you out, or even worse, use shared hosting (a horror story that’s explained in Chapter 6).
By refusing to rely on these *AMP bundles, you’ll be forced to climb the learning curve of installing a server and other software by hand—knowledge that’ll be useful in more ways than one if you’re serious about this career path. Besides, nailing down the basics is really not that hard, as you’ll see later in the book.
Say app1 and app2 are built on PHP 5.3, run MySQL 4.0, and are intended to go live on a server powered by Apache (the server software). Then, there’s a new requirement: make sure app1 works on PHP 5.6 and MySQL 5.1, and can be powered by Nginx (another server program that’s competition to Apache, pronounced “engine x”). Uh-oh, what now?
We could update PHP to a newer version and check whether app1 still works, but how do we then keep developing app2 without accidentally using code that’s unavailable in PHP 5.3 if our entire computer is now running 5.6? Likewise, we could upgrade MySQL to 5.1 and check that it still works, but how do we know MySQL didn’t throw out some old features in version 5+ that would break app2 even if we fixed app1 to work on 5.1? After all, app2 still needs to work on 4.0 because it’s probably still deployed on such a production server. Heck, how do we handle the Apache versus Nginx problem? Do we install both web servers on our computer and test for each? How do we switch them out? How do we ensure that we remember to test our site on one while the other is running?
And that’s just for two apps. Now imagine if you had to deal with a dozen applications from ten different clients, each with different requirements. It all stops being fun very, very fast.
This separation of different software versions is easy to solve by means of virtual machines, which we’ll talk about in Chapter 4.
Finally, what if we try to install a new version of PHP, but something goes wrong? This scenario is especially common in OS X and Linux―now none of the PHP versions we have installed on the machine work and it’s proving impossible to get a single site to run. What a mess! Instead of easily reverting to a previous running state, we’re forced to spend the entire day debugging our own system and trying to make it run―not necessarily the right version, but just run.
Wouldn’t it be great if we could just enter a command and have things go back to the way they were 10 minutes ago? Well, we can! This, too, will be demonstrated in Chapter 4.
This complicated-sounding phrase is actually very simple―we’ve actually indirectly touched on it before. Production/development parity means nothing more than having the production and development environment as similar as possible to each other, preferably identical, so that anything you develop will automatically run in production without any excessive configuration or additional debugging or tweaking.
Achieving parity is very important for one’s workflow due to the enormous amount of time it saves. Avoiding having to do any additional work for your application to run in production means having the freedom and time to focus on important business-related logic problems that actually benefit your application’s context, rather than being stuck in a rut of constantly playing catch-up. Making a change in development and then having to make two changes in production for that change to become apparent is tedious at best and detrimental to a project’s health at worst. You never know who on the team will slip up and cause the app to greet people with an error screen.
The best way to achieve parity is by having the exact same software running in your development environment as you do in your production environment. For example, if you’re aiming to deploy your application to production onto a server running the Ubuntu Linux version 14.04 operating system, it’s best that you develop on this operating system as well. However, what if we were running Windows, because we like to consume advanced multimedia content such as games, or we need powerful image and video manipulation software that just cannot exist on a Linux OS? Should we forsake all our other interests, install Linux over Windows, and strive for parity over anything else? Or should we just forsake parity and risk it while keeping our computer powerful, beautiful, and stable, sticking to our operating system of choice?
Fortunately, there’s a third way that allows you to achieve the best of both worlds: virtual machines (covered in Chapter 4).
The last aspects of the application environment we need to touch on is ensuring that the app is fast (performance) and bug-free (debugging). This section is entirely theoretical; it’s just so you know what to expect later on when we come across some of these terms.
Performance is achieved through various methods of optimization. Contrary to the word’s meaning, in application development optimization often has several layers and is rarely the change that immediately brings about the perfect solution. Performance includes, but is not limited to, several areas:
- Optimizing the database
Often the slowest part of any website, the database can benefit from additional optimizations after it’s been running for a while and the bottlenecks (the parts that are the slowest because they’re unable to process the number of incoming requests fast enough) become apparent. Methods for database optimization include setting up indexes, splitting reads and writes, changing database engines, caching fetched data, and other mystical-sounding phrases.
- Optimizing the front-end assets
- Optimizing the back end
This is also a compiling/building step. Test files are ignored, and files are merged into bigger ones to use instead of a million smaller ones. Some PHP applications are even compiled into another programming language such as C++, which is much, much faster.
Caching is saving previously needed files and responses for later, with the expectation of them being requested again. If you ask the database for the total number of users in your database, it will count them and give you the number. If you make it save this number for later (that is, cache it), next time it is asked it can just grab the already prepared information. When you ask the server “What do I get if I visit mysite.com/user/5?”, it will tell you. If you tell it to remember the answer next time the question is asked, there’s no need for the server to look as it already knows. Caching is so important in web development―there’s a common saying that “cache is king.” It can mean the difference between life and death for your application when a huge surge of traffic suddenly happens.
Debugging is tightly coupled with performance. Besides a nasty error screen for your users, a bug in the code can cause execution locks, holdups in your code where there should be none, repeated and unnecessary queries into your database, and more.
So, how does one measure performance or find bugs? There are many tools for profiling PHP applications (that’s what finding bugs and measuring the performance of various aspects of your application is called). Two of the better ones are Z-Ray and Blackfire (we won’t be covering them in this book as they are outside of its scope).
Warning: Beware Micro-Optimization
It’s important to note that a common newbie error is micro-optimizing. For example, it was once believed that using single quotes with strings (
$var = 'Some String') was faster than double quotes (
$var = "Some String"). The performance gains such an optimization can bring to the table are negligent and almost always insignificant; instead, improving a complex SQL query or caching a remote HTTP call will always be an order of magnitude greater. When in doubt, use benchmarks and real data (such as those from Z-Ray or Blackfire), and never your gut.
In this chapter, we explored the application environment, covering the various ecosystems present around your application in a given phase of its life cycle. We talked about virtual hosts and configuring your computer to redirect website URLs to your own PHP installation rather than looking for results online, and we discussed the all-important development/production parity.
If it all seems overly complex, don’t despair. This is only because we’ve dealt almost exclusively with theory so far―theory that is necessary to bravely proceed into the practical realm. In the following chapter, we’ll get our hands dirty with some virtual machines.
In the application universe, testing the individual components is referred to as unit testing―the testing of each individual set of code so that you know it works.
For example, a part of your application might have the ability to remove local symbols from every name and turn them into US-friendly letters. My last name “Škvorc” would thus be turned into “Skvorc.” Turning Škvorc into Skvorc is a small set of code, or a unit. This unit is testable; that is, for any given input of “Škvorc” I expect an output of “Skvorc.” I can then write a unit test, which is a file that defines the input and desired output, and when I run it, it tests whether or not this functionality still works. If, two months later, I change something in my application, I can easily run this test (which is still there) and check that this conversion still works. This sort of workflow ensures that you can upgrade your application later on without fear of breaking something you built before and forgot about. In our smartphone analogy at the beginning of the chapter, a single testable unit can be the touchscreen, or the battery.