You'll Never Believe What One Developer Did With compact()

I love PHP, and everyone that hates it needs to chill out! I’ve seen so many questions on quora like this one that carry an implicit dig on the language. The questioner starts with the assumption that PHP sucks. I won’t get into the reasons why they are wrong, for that you can just read the answers to the question in the link. But It did get me thinking that PHP is huge. So much of the web is coded in PHP.

 

We all know how easy it is to get stuck in one way of doing things. For me though, doing things the same way over and over again has that annoying effect of making work feel like ... well, you know .. work. That's boring. I’m a full stack developer who spends just as much time writing in PHP as I do writing HTML or JavaScript or SASS or LESS or whatever anyone is doing these days. And I realized that when I’ve been switching between languages, I’ve also been flipping a switch in my head and just assuming that PHP can’t do things that I can do in something like Node.JS with JavaScript. So, I decided to start feeling around to see if there are new, better, or just different ways of doing things in PHP that maybe I had not thought of yet. Here are a bunch of things that I learned that, now that I know them, I just can’t live without.

 

Here’s what I’ll cover:

  • compact & extract
  • List
  • Anonymous functions and Closures
  • Declaring your conditionals as variables

 

Before I get started, let me ask you this one question - Why did the developer quit their job? Because they didn’t get arrays!!!! Get it?! Ok ok I kid I kid. Moving on.

compact & extract

 

You probably know about the `implode` and `explode` functions. These PHP functions operate on strings and arrays and can be thought of as each other's opposite. `implode` takes a numerically indexed array and converts it to a string separated by the glue that you pass it. It's like, oh you have 100 bricks, let's smash them together with this concrete (is that how brick walls are made? I don’t know). `explode` does the opposite: It takes a string and kablooey! It's now an array based on the delimiter you pass it (is deglue-er a word? If not, it should be).

 

If you are familiar with these functions, you might be delighted to hear that PHP has more functions that operate on variables and associative arrays in a similar bi-directional manner. `compact` and `extract` do just this. `extract` takes an associative array and extracts all of the keys as variables into the current scope and defines them by their values in the array. Example:

 

<?php
$assoc = [
 
'name' => 'Josh',
 
'age' => '30',
 
'height' => "5' 8\"",
 
'weight' => 'noneya beeswax'
];

extract($assoc);


echo $name;
// renders Josh
echo $age;
// renders 30
echo $height;
// renders 5' 8"
echo $weight;
// renders 'noneya beeswax'

 

I find this method useful for passing data to a PHP template or for passing data into a function where you know all of the keys before hand and that all of the keys will be defined. Otherwise, you might get into an overwhelming if(isset($blah)){ //then do something } habit and that kinda defeats the usefulness of `extract`.

 

Oh and on that if(isset($blah) { // blah blah blah } note: New in PHP7 is a “null coalesce operator.” So now you can now do things like if ($sayHI ?? true) { echo "Hey there!"; }. Here if `$sayHi` is a variable that exists and is not null, then it will use the value of that variable. But if it’s no, it will default to true. But I digress.

 

`compact` does just the opposite. Let's say you have a ton of variables floating around the scope that you are working in, you want to take each variable and create an associative array to then pass that array on to a script or function. You could do it this way:

 

<?php

$name = 'Xaq';
$age =
'Probably younger than Josh';
$weight =
'Noneya';
$height =
'Definitely taller than Josh';

$assoc = [
   
'name' => $name,
   
'age' => $age,
   
'weight' => $weight,
   
'height' => $height
];

 

Even as a programmer that hurt my fingers and felt annoyingly repetitive. Wouldn't it be nice to just drop each variable into an array and have it automatically defined in the array by its variable name? Well guess what. You can!

 

<?php
// with our above defined vars
$assoc = compact('name','age','weight','height');

 

Boom! Done! And wasn't that easy?! This creates an associative array with each of our variable names as keys and their values as the array key's value.

list

 

Ok, and now last on these array operator, let me introduce you to my new favorite one: `list`. `list` is an operator that takes any number of variables. Unlike other functions and operators, `list` works on the left hand side of the assignment and you set it equal to the a numerically indexed array that you want to essentially extract the variables for. So here’s an example:

 

<?php
list($age, $height, $name) = ["30", "5'8\"", "Josh"];

echo $age;
// renders 30
echo $height;
// renders 5'8"
echo $name;
// renders Josh

 

If you are wondering why I think this is awesome, it's because here’s how I’ve been doing this for the last 6 years:

 

<?php
$joshAttributes = ["30", "5'8\"", "Josh"];
$age = $joshAttributes[
0];
$height = $joshAttributes[
1];
$name = $joshAttributes[
2];

 

As you can see, condensing 4 lines of code down to one is less work. And you know how game I am for less work.

Anonymous functions and Closures

 

Alright, got it? Still with me? Cool, let's move on to some slightly more complicated concepts. If you have at all worked with JavaScript, then you might be familiar with the concepts of anonymous functions and closures. Here's a brief JavaScript example:

 

// JS code

// anonymous function stored in a variable
var myFunction = function () {
   
console.log('Hey there person');
}


// function passed directly into another function (aka closure)
function anotherFunction(age, nameCB) {
   
var ageDec = nameCB(age);
   
console.log(ageDec);
}

anotherFunction(
30, function (a) { return 'Josh is ' + a + ' years old'; });
// this console logs 'Josh is 30 years old';

 

If you are not familiar with closures, I would not advise starting with the wikipedia article on them. If you are like me, this will lead you down a dark path of googling things like 'lexical' and 'first-class citizen'. Rather, I would look at a few practical examples like the responses to this Stack Overflow question, "What is a practical use for a closure in JavaScript?".

 

Since PHP5.3, PHP has actually supported closures as well. You might be thinking, "ahhhhhh ... ok, but why?" Well let me tell you! Firstly, using closures prevents any accidental namespace collisions. This is to say that you can have a function named `myFunction` in the parent or global scope and a variable named `$myFunction` that is assigned a function in any of your children scopes. Secondly, closures are a great way to store pieces of logic that you know you need to be flexible depending on the conditions in which they are called. (Here's an awesome resource that I stumbled upon for researching this post.)

 

Ok, so let’s say you have the following functions:

 

<?php

function myAwesomeFunction ($title) {
   
return function ($name) use ($title) {
           $name .=
' the ' . $title;
       echoIsAwesome($name);
   };
}


function echoIsAwesome ($string) {
   
echo $string . ' is super awesome!<br>';
}

 

In this example, we have a function `myAwesomeFunction` that returns a function. We consider the returned function an anonymous function because this function doesn't occupy any namespace of its own. It's a closure because it’s defined within the function scope of `myAwesomeFunction` and thus can access variables that are available to that scope (here it's using the $title variable).

 

We also have a function called `echoIsAwesome` that simply takes a string and appends ` is super awesome!`  and prints it out.

 

So, let’s say that you are building a page that lists out employees of an organization and these employees are organized by title. On this page you might want to declare the awesomeness of each employee. Using these functions above you can do something like the following:

 

$orgChart = [
   
'Co-founder' => [ 'Allyson', 'Jared' ],
   
'Project Manager' => [ 'Danielle', 'Kristin' ],
   
'Digital Strategist' => [ 'Justyn' ],
   
'Web Developer' => [ 'Xaq', 'Casey', 'Josh' ]
];


// now let’s loop through the $orgChart titles and employees and print each employee
foreach ($orgChart as $title => $employees) {
   $printFunc = myAwesomeFunction($title);
   
foreach ($employees as $name) {
       $printFunc($name);
   }
}

 

This will output the following:

 

Allyson the Co-founder is super awesome!
Jared the Co-founder is super awesome!
Danielle the Project Manager is super awesome!
Kristin the Project Manager is super awesome!
Justyn the Digital Strategist is super awesome!
Xaq the Web Developer is super awesome!
Casey the Web Developer is super awesome!
Josh the Web Developer is super awesome!

 

This is obviously a super simple example that may not even require a closure but just imagine that you wanted to do some more complex string concatenation that is 10 lines long and on top of that write in a db call to verify that the name of the employee exists in the database before calling the `echoIsAwesome` function and that db call would take 15 lines of code. For other developers who might be stopping by to fix something small while you are busy on other projects, reading a 6 line foreach loop with variable names that help describe the logic would be easier to read than a 27 line foreach loop with lots of concatenation and db calls. Or perhaps you are using this function on multiple pages for multiple reasons, and later you decide that you want to change that concatenation to something else and make it automatically percolate up to all the places where you are replicating this behavior throughout the website. Doing it this way means that you have one well-encapsulated spot where you can change the code, instead of hunting and finding all the foreach loops you've written throughout the site.

Declaring your conditionals as variables

 

Finally, the last trick I'd like to discuss is one that I assumed was solely for readability’s sake but I later found super helpful for performance and structure: 'Declaring your conditionals as variables'.

 

Let me just say that Rad Campaign builds a ton of Drupal websites and everyone on the team here are definitely Drupal pros. When I started at Rad Campaign, I only knew two things about Drupal: 1) lots of websites use Drupal as the framework on which they built their CMS on, and 2) all of my developer friends would take a deep breath whenever I would ask them about it. Now, after working at Rad for more than a year, I've realized that for how complex and confusing Drupal can be, under the hood is a rich world of great ideas in code. I learned this last idea when I was reading the Drupal Coding Standards on conditionals and line length. Specifically, the Drupal Coding Standards says this:

 

"Control structure conditions should also NOT attempt to win the Most Compact Condition In Least Lines Of Code Award™ ... [omitted code example] ... Instead, it is recommended practice to split out and prepare the conditions separately, which also permits documenting the underlying reasons for the conditions ... [omitted code example]"

 

This is to say, don’t do this:

 

<?php

if (($rad == 'great' && $rad == 'awesome websites') || ($otherWebAgencies == 'just alright' && $rad == 'better') || ($josh == 'great' && $josh == 'decent code')) {
        
echo 'hire rad!';
}

else {
        
echo 'retire from the internet all together and enjoy the quiet bliss of solitude deep in the woods for the rest of days';
}

 

Ooofff, that if statement is lenggggtttthhhhhy. We can clean it up by defining our conditionals and in doing so make the code more readable:

 

<?php

$radIsAwesome = ($rad == 'great' && $rad == 'awesome websites');

$otherAgenciesAreNotAsAwesome = ($otherWebAgencies == 'just alright' && $rad == 'better');

$joshIsAlright = ($josh == 'great' && $josh == 'decent code');

if ($radIsAwesome || $otherAgenciesAreNotAsAwesome || $joshIsAlright) {
        
echo 'hire rad!';
}

else {
        
echo 'retire from the internet all together and enjoy the quiet bliss of solitude deep in the woods for the rest of days';
}

 

Here, even without comments (shame on me), the code is so much more readable. We can see clearly from the naming of the variables what the if statement is evaluating without having to work too hard to visually parse it out. And for future code fixers, that’s a plus. These little things have real world consequences as well. Any little thing you can do to make your code more coherent will make it easier to fix, which will save someone else time and money.

 

CONCLUSION

Like I said before, PHP is huge. It's a common cliche in programming that there are many ways to skin a cat (no animals were harmed in the production of our code). There are many ways of doing things, and PHP is so vast that certainly there are tips that are not presented here and that I may not even know. If you know of any that should definitely be on our list, we'd love to hear from you. Drop us a note at info@radcampaign.com.

 

Oh, yeah, and thanks for reading this far!

Tags: 

More on the Blog

July 8, 2016
Screenshot of Facebook one-click to donate button

Is Facebook’s One-Click Donate Button a Game Changer?

Facebook recently rolled out its one-click donate button for nonprofits.

January 1, 2016

How Nonprofits Can Stay Relevant in the Age of Media Convergence

As we head into 2016, nonprofit leaders need to focus on the intersection of technology, media, and consituent engagement.

April 27, 2018
100 cardboard cutouts of FB founder/CEO Zuckerberg outside the US Capitol in DC on 4/10/2018. Avaaz is calling attention to what the groups says are hundreds of millions of fake accounts still spreading disinformation on FB. -SAUL LOEB/AFP/Getty Images

Facebook Faces Congress And Why This Is A Detriment to Nonprofits

While Facebook has been under investigation by Congress, we’ve been seeing lots of changes on all of the networks that connect to the mega social network because of changes to the Facebook and Instagram APIs that are “in