Just a slug generator. I'm wondering if this can be simplified any further.

Many thanks.

function slug($string) {

    // Replace all non letters, numbers, spaces or hypens
    $string = preg_replace('/[^\-\sa-zA-Z0-9]+/', '', mb_strtolower($string));

    // Replace spaces and duplicate hyphens with a single hypen
    $string = preg_replace('/[\-\s]+/', '-', $string);

    // Trim off left and right hypens
    $string = trim($string, '-');

    return $string;

echo slug('-- This is an example     of an ------ article   - @@@ ..,.:~&**%$£%$^*'); // outputs "this-is-an-example-of-an-article"

Updated version based on feedback:

function createSlug($slug) {

    $lettersNumbersSpacesHyphens = '/[^\-\s\pN\pL]+/u';
    $spacesDuplicateHypens = '/[\-\s]+/';

    $slug = preg_replace($lettersNumbersSpacesHyphens, '', $slug);
    $slug = preg_replace($spacesDuplicateHypens, '-', $slug);

    $slug = trim($slug, '-');

    return mb_strtolower($slug, 'UTF-8');

echo createSlug('-- This is an example ű of an ------ article   - @@@ ..,.%&*£%$&*(*');

2 Answers 2

  1. You could create a few explanatory local variables:

    $lettersNumbersSpacesHypens = '/[^\-\sa-zA-Z0-9]+/';
    $spacesAndDuplicateHyphens = '/[\-\s]+/';


    $lettersNumbersSpacesHypens = '/[^\-\sa-zA-Z0-9]+/';
    $slug = preg_replace($lettersNumbersSpacesHypens, '', mb_strtolower($slug));
    $spacesAndDuplicateHyphens = '/[\-\s]+/';
    $slug = preg_replace($spacesAndDuplicateHyphens, '-', $slug);

    These would eliminate the comments. (I haven't checked the regexps, other names might be more appropriate.)

    Reference: Chapter 6. Composing Methods, Introduce Explaining Variable in Refactoring: Improving the Design of Existing Code by Martin Fowler:

    Put the result of the expression, or parts of the expression, in a temporary variable with a name that explains the purpose.

    And Clean Code by Robert C. Martin, G19: Use Explanatory Variables.

  2. slug could be renamed to cleanSlug (contains a verb) to describe what the function does.

  3. I'd rename the $string variable to $slug It would be more descriptive, it would express the intent of the variable.

  4. I'd use a whitelist instead of the blacklist. Defining the allowed characters (A-Z, 0-9 etc) would create proper URLs from URLs which contain special characters like é or ű.

  • \$\begingroup\$ Thanks. I've updated my original question with some changes. Didn't notice the problem with different characters before, this has now been fixed. \$\endgroup\$ Commented Mar 14, 2014 at 15:28
  • \$\begingroup\$ @AlexGarrett: You're welcome. I've updated the answer a little bit. \$\endgroup\$
    – palacsint
    Commented Mar 14, 2014 at 15:38

Just a small extension to what has been written. If your slug generator is not for an assignment but for actual deployment a lot of frameworks use slug helpers already. I use Laravel, however Laravel has an entire class so that might be messy.

Before Laravel, Codeigniter was the rapid deploy system and their slug system is pretty robust.

Take a look at the slug file. Now mind you they have formatted it into a class with a lot of comments - but if you omit everything you can compare their's and yours and see where the middle ground can be.

Codeigniter Slug Class

Note - I'm adding this extra bit because as always you shouldn't re-engineer code if its been done and done well.

  • \$\begingroup\$ Great, thanks for the advice. I actually adapted this code from the Laravel framework. It's for education purposes, so wanted to simplify it so it's easier for beginners to grasp. But I completely agree, good hardened code shouldn't be rewritten if not necessary. \$\endgroup\$ Commented Mar 14, 2014 at 15:30
  • \$\begingroup\$ I recommend the codeigniter's version instead because i had to reverse engineer it for legacy non MVC code and it works better as as stand-alone function rather than a class (once you take out the clutter) \$\endgroup\$
    – azngunit81
    Commented Mar 14, 2014 at 15:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.