All posts by Jonathon

Scaling Your Website: Three Stages

So, you have A Big Idea that will Revolutionize The World. Naturally, people will flock to your site and engage with it. Naturally, you are concerned about whether your infrastructure can handle success. You wish to plan for success, it would be foolish not to, eh? Don’t let enthusiasm (or ignorance) lead you to premature over-optimization. After all, your Big Idea has not yet passed the test of time.

Here I will describe the three early stages commonly encountered when scaling a new website or startup application. Each one builds off the previous ones, starting with the lowest-hanging fruit and working up. Continue reading

What Is Wrong With PHP’s Semaphore Extension

Lack of a true Semaphore

sem_release() releases the semaphore if it is currently acquired by the calling process, otherwise a warning is generated.
http://php.net/manual/en/function.sem-release.php

By far the worst, this limitation makes a whole class of problems much more difficult to solve, and in fact means that PHP’s Semaphore extension, despite the name, is really a mutex (a semaphore with ownership, i.e., only the acquirer may release). Furthermore, it is inconsistent with the behavior of equivalent functions in other languages such as C and Python.

Please see phm\Lock\Semaphore for a kludgy workaround using mutexes, shared memory, and a message queue. Continue reading

Roll your own MAMP development environment

Pre-packaged MAMP, LAMP, and WAMP stacks have been common on developer’s computers for years. Such packages are convenient because they provide a single-step install process, with all components in the server stack preconfigured to work together, and off you go.

Except when they don’t.

I’ve learned from experience that these packages have ways of making you pay for the convenience you enjoyed up front. If you have ever needed to:

  • Install a PHP extension that wasn’t already provided in your stack
  • Run a specific version of PHP or MySQL
  • Install PEAR packages
  • Install SSL certificates
  • Run command-line PHP scripts

…you may have encountered some ugly, time-wasting surprises along the way.

It pays to know your environment inside and out. Today, it is quite easy to roll your own Apache-MySQL-PHP stack on Windows, Linux, or even Mac OS X. Continue reading

Box drawing in PHP

Back in the “good old days” of MS-DOS, you could draw lines, boxes, filled areas (think progress bars), and more using the extended ASCII character set (AKA code page 437).

While writing a simple command-line utility in PHP I wanted to use the full block () and light shade () characters to create a simple progress bar that is a bit nicer than the typical =========....................

Like this:

█████████████████░░░░░░░░░░░░░░░░░░░░░░░ 42.5%

Instinctively, I turned to PHP’s chr() function and looked up the extended ASCII codes for the characters I needed. Boy, was I disappointed when my progress bar was nothing but a series of un-useful question marks. Surely PHP can render simple ASCII characters, I thought.

It might have gone differently if I had been using a PC, but I do 100% of my development these days on a Macbook Pro. It so happens that the bash shell in UNIX, Linux, and Mac OS X all use UTF-8 encoding by default, not CP437. (Of course, your terminal font will need to support UTF-8 characters for this to work.)

So, I just needed to find the UTF-8 codes for the characters I needed and use those instead of the old familiar CP437 ones. However, the results weren’t much better.

After an hour or more of Googling and experimentation, I finally realized that chr() doesn’t do UTF-8. I found various suggestions on how to produce the desired characters using custom functions and the like, but the best way turned out to just use a good ‘ol HTML entity and run it through html_entity_decode:

$block = html_entity_decode('█', ENT_NOQUOTES, 'UTF-8'); // full block
$shade = html_entity_decode('░', ENT_NOQUOTES, 'UTF-8'); // light shade

Now, a progress bar isn’t exactly a box, so let’s demonstrate:

$tl = html_entity_decode('╔', ENT_NOQUOTES, 'UTF-8'); // top left corner
$tr = html_entity_decode('╗', ENT_NOQUOTES, 'UTF-8'); // top right corner
$bl = html_entity_decode('╚', ENT_NOQUOTES, 'UTF-8'); // bottom left corner
$br = html_entity_decode('╝', ENT_NOQUOTES, 'UTF-8'); // bottom right corner
$v = html_entity_decode('║', ENT_NOQUOTES, 'UTF-8');  // vertical wall
$h = html_entity_decode('═', ENT_NOQUOTES, 'UTF-8');  // horizontal wall

echo $tl . str_repeat($h, 15)  . $tr . "\n" .
     $v  . ' Hello, World! '   . $v  . "\n" .
     $bl . str_repeat($h, 15)  . $br . "\n";

Voilà!

UTF-8, once you get used to it, actually provides many more possibilities than CP437 did back in the MS-DOS days. Enjoy!

Just-in-time $GLOBALS

Update—Turns out, this isn’t actually a bug. Rasmus Lerdorf has already explained this behavior in response to a bug report:

This is not a bug. It is a documented optimization feature. See http://php.net/manual/en/ini.core.php and look for the section on auto_globals_jit with the big pink warning which says, “Usage of SERVER and ENV variables is checked during compile time so using them through e.g. variable variables will not cause their initialization.”


I encountered an odd bug in PHP 5.3.10 while attempting to loop through all the major superglobals ($_SERVER, $_GET, $_POST, etc). Here is what I found, if you can shed any light on why this happens, or if you can confirm that it isn’t just me, I would greatly appreciate it!

Test Case

<?php
var_dump($GLOBALS['_SERVER']);
// These behave the same way:
// $var = '_SERVER'; var_dump($$var);
// var_dump(${$var});

Expected Behavior

$GLOBALS["_SERVER"]: array(27) {
...
}

Actual Behavior

NULL

Workaround

What makes this so strange is that if you access $_SERVER (or ${'_SERVER'}) directly in the code anywhere—even if it doesn’t actually get executed—this bug does not manifest itself! In other words, this works just fine:

<?php
var_dump($GLOBALS['_SERVER']);
exit;
$var = $_SERVER;

Lone Star PHP takeaways

Thanks to the guys at Engine Yard, I won a free pass to the Lone Star PHP community conference in Dallas, TX this year. Due to the choice of subject matter and presenters, I think I enjoyed this conference even more than last year’s PHPCon in Nashville. Here are some of the highlights.

Day 1

!Normal===Awesome!

Cal Evans inspired us all to go out and build awesome stuff, and that we owe a debt to the giants who came before us and gave, to give to those coming after.

  • “This stuff is hard. If it looks easy, it’s because I’m good at it.”
  • Get involved somewhere.
  • Be a builder, a speaker, a teacher.

Building Testable PHP Applications

Chris Hartjes delivered a really helpful talk on testing applications. One of the big obstacles of unit testing for me was mock objects. Chris did a good job explaining how they are used in the context of PHPUnit. Key takeaways for me:

  • Automate test execution.
  • Following the law of demeter will make your applications easier to test.
  • Code in a framework-agnostic and environment-agnostic way.
  • PHPUnit provides methods for setting up mock objects, so you don’t have to actually define those classes.
  • Test private/protected methods and properties by using a Reflection hack. Etsy’s PHPUnit extensions can automate this.
  • Don’t access the database in Unit tests, use mock objects instead. Filesystem access can be mocked using vfsStream.
  • Some applications resist testing, no matter what. If you cannot refactor, you can still automate tests with Behat.
  • If you don’t test, Chris will cut you!

See his slides at SpeakerDeck.com.

PHP Extensions for Dummies

Elizabeth Smith laid bare the innards of PHP in her intro to PHP extension development. Much of it was unintelligible to me since I don’t (yet) know C. However, now I know who to go to if I need help compiling an extension! If I can navigate the dependencies, I’d like to try compiling a non-thread-safe Windows build of php_wkhtmltox for a future blog post.

Pixel Punching with PHP

Bob Majdak‘s presentation compared the usage and performance of GD2 and IMagick across a number of common image manipulation tasks. IMagick is better in almost every way.

See his slides at SpeakerDeck.com.

Day 2

It Was Like That When I Got Here: Steps Toward Modernizing a Legacy Codebase

Paul Jones‘ keynote did not disappoint. With insight and humor, Paul dismantled the problems with legacy codebases and presented a logical methodology to improving your life when you are forced to inherit a big stinkin’ pile of spagetti code.

  • No matter how bad you want to, resist the urge to throw it out and rewrite.
  • You’ve nothing to lose. Either bear the pain of bad code, or bear the pain of refactoring bad code. May as well put the suffering to some use.
  • Move class files to a common base directory and autoload, removing require/include calls as you go.
  • Change class names as you go, if needed.
  • Wrap procedural functions in a class, so that it can be autoloaded.
  • Replace globals incrementally, moving them first to the constructor, then replacing them with dependency injection

SOLID – Not Just a State Of Matter, It’s Principles for OO Propriety

Chris Weldon laid out five principles to get the most out of object oriented development.

  • Single responsibility: each class should do one and only one thing.
  • Open/Closed principle: each class is open to extension, but closed for modification. Don’t break stuff.
  • Liskov Substitution principle: replace if…else constructs and prevent exceptions by using typed collections.
  • Interface segregation: each interface should be as focused as possible, so that it can be used by as many classes as need it. Similar to the Open/Closed principle, applied to interfaces.
  • Dependency Inversion: injection dependencies from the outside, don’t couple on the inside.

Fast, Not Furious: Performance Tuning that Works

Davey Shafik demonstrated how to use xhprof/xh-gui and Memcache to optimize your PHP application.

  • 1. Benchmark. 2. Profile. 3. Change.
  • Profiling affects performance, similar to quantum observation.
  • Benchmarking tests actual runtime, from start to end.
  • Namespacing Memcache keys can help overcome the 1MB size limit
  • Create new namespaces, don’t clear the cache. Garbage collection will clean up the old unused namespaces.
  • “Hardware is cheap, programmers are expensive” only holds when you take care of your hardware.
  • Don’t make assumptions, test everything sequentially.