Generate Perfect Initials using PHP

Published on
Generate Perfect Initials using PHP

Update March 26, 2022
I’ve updated this to be compliant with UTF-8 characters.

Most of the web apps you use have a placeholder image for your avatar. If the app is using Gravatar to generate the avatars, you will get the mystery man if no user exists. Applications like Trello take it to the next level by displaying initials of the user if they have no avatar. Today we are going to learn how to generate those using a few lines of clean PHP.

Scenarios

First, we need to layout is all the possible ways we want to generate initials, and what the expected outcome would be. Defining our requirements up front will save us time in unexpected outcomes and make our code more reliable. I can see four basic requirements for our generator.

  1. Name has two words
    • eg: Chris Blackwell should translate to CB
  2. Name has only one word
    • eg: Chris should translate to CH
  3. Name has one word with two capitals.
    • eg: MacDonald should translate to MD
  4. Name has more than two words.
    • eg: Chris Shane Blackwell should translate to CB

Did I miss any? If so please leave a comment and I’ll update the article.

Creating our Class

I like to get things started by stubbing out any methods I normally need. Let’s create our class and stub out any methods we need. When I’m using a utility class like this, I make a generate method so I know what the primary action is.

class Initials
{
    /**
     * Generate initials from a name
     *
     * @param string $name
     * @return string
     */
    public function generate(string $name) : string
    {
        // @TODO
    }
}

The generate method takes one parameter called $name that must be a string and returns a string. Type hinting protected us from other coders trying to pass unexpected types to our code.

The first thing we need to do is break the name into an array of words.

$words = explode(' ', $name);

Any string we pass into as the $name parameter will give us an array of all the words in the string. Passing my name of Chris Blackwell will give us this array:

array(2) {
  [0]=>
    string(5) "Chris"
  [1]=>
    string(9) "Blackwell"
}

Looking at this array gives us insight into our easiest route to success. Taking the first letter of the each of the words in the array will give us our initials. We can use our $words array and take care of our basic requirement of a full name with one line:

public function generate(string $name) : string
{
    $words = explode(' ', $name);
    return mb_strtoupper(
                mb_substr($words[0], 0, 1, 'UTF-8') . 
                mb_substr(end($words), 0, 1, 'UTF-8'), 
           'UTF-8');
}

This line takes the first letter of the first word and the first letter of the last word. It wraps those methods in a strtoupper method to capitalize the initials if they were not already.

While this covers most of the scenarios we will see, we still have the single word case “Chris” and the scenario where things are capitalized in one word “MacDonald”.

Catching the Edge Cases

Since our code only works with names that have two words or more, we will wrap it in an if block to catch them.

public function generate(string $name) : string
{
    $words = explode(' ', $name);
    if (count($words) >= 2) {
        return mb_strtoupper(
                mb_substr($words[0], 0, 1, 'UTF-8') . 
                mb_substr(end($words), 0, 1, 'UTF-8'), 
            'UTF-8');
    }
}

We’re going to add another method to make initials from a single word. I like naming my functions very descriptive, so we will call this function makeInitialsFromSingleWord. Exactly like our generate function, this one takes one parameter called $name that must be a string and the function returns a string.

protected function makeInitialsFromSingleWord(string $name) : string
{
    // @TODO
}

The first thing we want to do in this function is filter out any capitals in the string. We will use the preg_match_all method to assign any capitals it finds to a variable called $capitals. If there are 2 or more capitals, we can use the first two for initials.

If there are less then 2 capitals, we will use the first two letters of the name and capitalize them.

protected function makeInitialsFromSingleWord(string $name) : string
{
    preg_match_all('#([A-Z]+)#', $name, $capitals);
    if (count($capitals[1]) >= 2) {
        return mb_substr(implode('', $capitals[1]), 0, 2, 'UTF-8');
    }
    return mb_strtoupper(mb_substr($name, 0, 2, 'UTF-8'), 'UTF-8');
}

Summary

We now have the ability to create initials just like you see on all your Trello cards. All four of our name scenarios have been verified to work. Do you think there is a way we could have extended this to cover more names? I’d love to hear your feedback!

Below is the code in it’s entirety

class Initials
{
    /**
     * Generate initials from a name
     *
     * @param string $name
     * @return string
     */
    public function generate(string $name) : string
    {
        $words = explode(' ', $name);
        if (count($words) >= 2) {
            return mb_strtoupper(
                mb_substr($words[0], 0, 1, 'UTF-8') . 
                mb_substr(end($words), 0, 1, 'UTF-8'), 
            'UTF-8');
        }
        return $this->makeInitialsFromSingleWord($name);
    }

    /**
     * Make initials from a word with no spaces
     *
     * @param string $name
     * @return string
     */
    protected function makeInitialsFromSingleWord(string $name) : string
    {
        preg_match_all('#([A-Z]+)#', $name, $capitals);
        if (count($capitals[1]) >= 2) {
            return mb_substr(implode('', $capitals[1]), 0, 2, 'UTF-8');
        }
        return mb_strtoupper(mb_substr($name, 0, 2, 'UTF-8'), 'UTF-8');
    }
}