TomNomNom.com

Blogging since 2008 until 2010

Syntax highlighting with PHP's tokenizer

While I was changing my design from light to dark, I hit a problem with my syntax highlighting: the colours were just too damn dark to see on a dark background. Because I only usually write about PHP, I just use highlight_string() for my syntax highlighting - rather than one of the more popular JavaScript syntax highlighters. To change the colours I can just call ini_set() to set highlight.keyword etc to whatever I want.

That's all fine and dandy, but one of the things I really wanted was to give 'users' the ability to switch to whatever style they want. That could get quite complicated (and slow) if I just used ini_set() to do it. That, and I'd rather it were possible without re-loading the page.

My solution is to hack together my own function for highlighting PHP, but instead of having it specify the colour of each section directly in the style attribute of the span tag (like highlight_string), have it specify a class that I can change the appearance of with regular old CSS.

And it looks a little like this:

<?php
function highlightPhp($source){
  $tokens = token_get_all($source);
  $output = '';
  foreach ($tokens as $token){
    if (is_string($token)){
      $output .= htmlEntities($token);
    } else if (is_array($token)) {
      list($id$text) = $token;
      $name = str_replace('_''-'strToLower(token_name($id)));
      $text = htmlEntities($text);
      $text = str_replace(
        array(" ",      "\\n"),
        array("&nbsp;""<br/>"),
        $text
      );
      if ($id != T_WHITESPACE){
        $text = "<span class=\\"phps-{$name}\\">{$text}</span>";
      }
      $output .= $text;
    }
  }
  return $output;
}

Note: As of about an hour after I posted this, the code above was highlighted with itself!

With CSS that looks something like this:

<style type="text/css">
  /* Don't use this CSS. Your code will look HORRIBLE ;-) */
  .phps-t-open-tag {color: #DD3333;}
  .phps-t-variable {color: #33DD33;}
  .phps-t-if,
    .phps-t-while,
    .phps-t-exit {color: #3333DD;}
  .phps-t-string,
    .phps-t-echo {color: #33DDDD}
  .phps-t-isset {color: #DD33DD}
  .phps-t-lnumber {color: #DDDD33}
  .phps-t-encapsed-and-whitespace,
    .phps-t-constant-encapsed-string {color: #DDDDDD}
</style>

It's a little primitive at the moment, and I haven't bench-marked it, but it seems to do the job.

And it does have one other advantage over highlight_string(): it provides much more granular control over the colours. highlight_string() only provides six possible colours (highlight.bg, highlight.comment, highlight.default, highlight.html, highlight.keyword, highlight.string), rather than all of these.

Hopefully I'll be implementing it here soon. I'll be sure to provide some benchmarks compared to highlight_string().

First posted: Wed, 07 Oct 2009 20:24:01 +0000