The Perl Review

Navigation: Home | Authors | Issues | Tags | Articles | Book Reviews

Perl and PHP are two extremely popular tools for generating dynamic web content. Both are shining examples of succesful open source development and are similar enough syntactically that distinguishing one from the other can sometimes be difficult. I provide an overview of the similarities and differences of syntax to serve as a guide for the Perl hacker who needs to do a bit of PHP, and the PHP hacker who needs to do a bit of Perl.

Introduction

It is no secret: there is more than one way to generate dynamic HTML. In some ways today's widespread use of Perl can be attributed to being in the right place at the right time when the Web took the world by storm in the mid 1990s. Of course it did not hurt that Perl was especially good at working with textual data.

Today the scenery has changed somewhat, and there are a wealth of options available to the web publisher who needs to produce interactive web pages, including Java, Python, ColdFusion, Active Server Pages, and PHP. Since many of these languages share C as a common ancestor, they share a lot of syntax as well. For example, PHP and Perl share so much syntax that it is possible to look at a block of code and not know if it is Perl or PHP:

$x[0] = 'The';
$x[1] = 'Perl';
$x[2] = 'Review';
for ($i=0; $i<3; $i++) {
    if ( $i == 1 ) {
        print 'PHP';
    } else {
        print $x[$i];
    }

    print ' ';
}

PHP and Perl share quite a bit more than syntax however. Both are two of the big success stories of the open source development model. Furthermore, when PHP was first released in 1995 as Personal Home Page / Form Interpreter (PHP/FI) it was actually a set of Perl programs. Today, PHP v4.0 has its own interpreter written in C, but it still holds to its Perlish roots. Its syntax draws heavily on the language features that made Perl such a popular tool for working with the Web and both can be embedded in Apache, the most popular web server (when this article was written 59.91% of the webservers (Netcraft Web Server Survey, September, 2002. ) on the Internet ran Apache, and of those 40.03% ran mod_php, and 30.79% ran mod_perl ( Apache Module Report, Security Space. September 1st, 2002.

Given their pervasive use, programmers may find themselves involved in a project where they need to build or maintain an application using Perl or PHP. Some may end up in a situation where they are encouraged to answer ``which is better Perl or PHP?''. A lot of programmers have strong opinions about this already. However, as Mark-Jason Dominus points out in his article Why I Hate Advocacy, "apparently it [is] inconceivable that there might be two right ways of doing something." The motivation to decide which solution is better sometimes clouds the issue from the start. Dominus examines a situation where the designer of the Perl Archive received complaints because part of the website was implemented with PHP:

One big problem with thinking and talking like this is that it means we can't learn anything new. Suppose that PHP has some advantage over Perl that would lead Jasmine to use it in place of Perl on her website. If that's true, wouldn't it be cool if Perl could copy that advantage in the next version?

It would be cool—this is precisely what has made Perl such an enjoyable language for me in the first place. Dominus's comments remind me of one of a talk Larry Wall gave ( Perl, the first postmodern computer language at Linux World 1999 in which he described Perl's postmodern design philosophy:

When I started designing Perl, I explicitly set out to deconstruct all the computer languages I knew and recombine or reconstruct them in a different way, because there were many things I liked about other languages, and many things I disliked. I lovingly reused features from many languages... I've [borrowed] over the course of the years from C, sh, csh, grep, sed, awk, Fortran, COBOL, PL/I, BASIC-PLUS, SNOBOL, Lisp, Ada, C++ and Python. To name a few.

This leads to another thing that Perl and PHP have in common: just as Perl borrowed liberally from other languages, so PHP borrowed from Perl.

The Basics

Like Perl, PHP is an interpreted language: the code that I write is read by an interpreter, which parses my instructions and then performs them. Since Perl predates the Web and is a general purpose language, the interpreter is generally known to run from the command line. On the other hand, Rasmus Lerdorf designed PHP to quickly build HTML content, so its interpreter is normally compiled directly into an Apache webserver. However, the Perl and PHP interpreters can run both ways: I can run the PHP interpreter from the command line in much the same way as Perl; and mod_perl allows me to embed the Perl interpreter directly into Apache for increased performance. There are differences in how the embedded interpreters behave: most significant is that out of the box mod_php does not cache compiled code while mod_perl does. Caching compiled code has a significant impact on performance and memory usage. Add-on packages allow PHP to cache results; see Caching PHP Programs with PEAR by Sebastian Bergmann.

Perl is a general purpose programming language whereas PHP is a specialized language for creating WWW applications. Both have their benefits: Perl can parse the human genome in addition to creating HTML. PHP's syntax leans towards generating HTML, and is not as overwhelming for new programmers. It is different from Perl since it uses an inside-out approach (although programmers are not required to use it this way). All PHP code is within special tags in an HTML file. When a PHP-enabled Apache encounters such a file it will generate the verbatim HTML, and hand off PHP code to the PHP interpreter.

In code listing PHP in HTML, the <?php ... ?> sections are XML style tags for flagging an area of the document for processing by PHP, although PHP supports other tagging schemes: SGML style, ASP style, and script style. The XML style is the most popular since it is compliant with the XHTML standard. This approach allows designers to easily focus on the HTML presentation while the programmers focus on the PHP portion. This approach is also a good way to introduce designers to the terminology and techniques of programming. In fact, the popularity of inside-out design has produced the EmbPerl Apache module which allows me to embed Perl code in HTML documents in much the same way.

PHP in HTML

<html> <body> <?php $time = time(); ?> <p>If you are using a Mac it has been <?php print $time; ?> seconds since January 1 1904.</p> <p>Otherwise it has been <?php print $time; ?> seconds since January 1, 1970.</p> </body> </html>

It also possible to write PHP in a more Perl like fashion, as in code listing Perl Style PHP. This example illustrates some general similarities between Perl and PHP: semicolons to end statements; whitespace; comments (although PHP natively supports C and C++ style comments as well); and the use of sigils $ to identify variables. PHP's function names are not case-sensitive, but variable names are. While it is not shown here, PHP and Perl both use C style curly braces to denote blocks of code.

Perl Style PHP

<?php $time = time(); print "<html><body>"; print "<p>If you are using a Mac it has been $time seconds since ". "January 1 1904.</p>"; print "<p>Otherwise it has been $time seconds since January 1, 1970.</p>"; PRINT "</body></html>"; ?>

Code Reuse and Documentation

One of the most distinguishing features of Perl is the Comprehensive Perl Archive Network (CPAN) which is a virtual library of Perl code that allows programmers to stand on the shoulders of giants who have come before. PHP has a similar resource called the PHP Extension and Application Repository (PEAR) which also provides access to reuseable code libraries. Since Perl has such a head start on PHP, PEAR is a mere shadow of CPAN, but PEAR is likely to change as PHP developers recognize the benefits of code reuse.

Perl and PHP documentation are both available online. I can embed my own documentation in both Perl and PHP programs. Perl uses the Plain Old Documentation (pod) format (see the perlpod manual page), and PHP uses phpdoc, inspired by javadoc, and is still in beta. Code listing pod shows a pod example and code listing phpdoc shows the PHP equivalent.

Pod

=head1 friend() To get a string saying someone is your friend, pass in your friend's name as a string and you'll get it back.

Code listing phpdoc shows the PHP equivalent to code listing pod. Although phpdoc is not integrated fully into PHP as pod is in Perl, like javadoc it has the benefit of explicitly defining the types of parameters that I can pass to a function, as well as its return values. Pod benefits from being a general purpose formatting language—I originally wrote this article in pod.

phpdoc

/** * To get a string saying someone is your friend, pass in your friend's * name and you'll get it back. * * @param string * @return string */ function friend ( $name ) { return( "$name is my friend" ); }

Scaling Operations

PHP and Perl allow me to store integer, floating point, and string data in the same type of variable: the scalar. Scalar variables use the dollar sign, $, to identify the variable name, and are the basic building block of other variable types. Having weakly-typed scalar variables is a great boon to web developers since it makes it easy to work with numeric and textual data interchangeably without having to worry about buffer overflows and the casting of variables to different types. Scalars values in Perl and PHP are limited by the C library type sizes (for numbers) and the amount of available memory (for strings)

Unlike Perl, PHP has native support for boolean values which allow me to assign the values true and false to a scalar variable. Perl supports booleans by evaluating a scalar as false if it contains 0, undef, or the empty string, and true otherwise. Being able to explictly assign a variable to true or false encourages a certain amount of clarity; however PHP also supports Perl's DWIMery—the only diffence being that like Java, PHP uses the keyword null instead of Perl's undef.

The standard comparison operators <, >, <=, >= and == are available to compare scalars. In general, the two languages do similar type casting behind the scenes to allow me to compare integer, float and string values in a meaningful way. However, the tests for equality which look similar but are actually quite different. Perl uses == for numeric and eq for string comparisons, both of which will do implicit type casting. PHP uses the == for both numeric and string tests of equality (with implicit type casting), and === as a test of equality without implicit type casting. Table comparisons shows the different behavior of == in particular can be the source of subtle errors for the unwary.

Comparison results

OperationPerlPHP
'2e' == '2c'truefalse
'TRS80' == 'trs80'truefalse

In addition, PHP has the <> operator which is an alias to !=. Neither language currently supports chained comparison operators (1 < $x < 10) but Larry has it slated for addition in Perl 6.

The usual cast of mathematical operators are present in both languages (+, -, *, /, %) as well as the postfix/prefix and bitwise opertators (++, --, |, &, ~, ^, <<, >>). Conspicuously absent from this list is the exponentiation operator, which is ** in Perl. PHP does not have an equivalent operator, but it does have the pow() function. The common mathematical functions in both languages include cos(), sin(), log(), sqrt().

The power and flexibility of Perl's string operations distinguished it early on as a tool for working with the Web, so it is hardly suprising that PHP has many of the same functions, albeit some have slightly different names. The most reknown of these string manipulation tools are regular expressions, which PHP supports via the preg_match(), preg_replace(), preg_split() functions. PHP also supports POSIX style regular expressions which "are less powerful, and sometimes slower, than the Perl-compatible functions" (Programming PHP by Rasmus Lerdof and Kevin Tratoe, p. 95 ). Rather than itemizing all the string manipulation functions in PHP and Perl, Table strings illustrates how to achieve similar ends with both languages.

String manipulations

PerlPHP
$a . $b				
lc($x)				
uc($x)				
ucfirst($x)			
$a <=> $b				
substr($x,0,1)		
substr($x,0,3) = 'abc'
index($x,$y)			
length($x)			
$x =~ tr/aeiou/z/		
$x =~ /perl/			
$x =~ /[aeiou]/		
$x =~ /perl/i			
$x =~ s/php/perl/		
$x =~ s/perl/php/g	
split/=/,$x			
split/(=)/,$x
$a . $b											
strtolower($x)									
strtoupper($x)									
ucfirst($x)										
strcmp($a,$b)										
substr($x,0,1)									
substr_replace($x,'abc',0,3)						
strpos($x,$y)										
strlen($x)										
$x = strtr($x,'aeiou','zzzzz')					
preg_match('/perl/',$x)							
preg_match('/[aeiou]/',$x)						
preg_match('/perl/i',$x)							
$x = preg_replace('/php/','perl',$x,1)			
$x = preg_replace('/perl/','php',$x)				
preg_split('/=/',$x)								
preg_split('/(=)/',$x,-1, PREG_SPLIT_DELIM_CAPTURE)

A Tale of Two Arrays

One of the real joys of programming in Perl are the array and hash data structures with their associated functions and syntactic sugar. Arrays and hashes automatically grow in size as needed and can be multi-dimensional. PHP also has built in support for arrays and hashes although they are not quite the same under the covers, and they are named differently. Perl distinguishes between scalar, array and hashes using the $, @ and % sigils, whereas PHP only uses the $. In some ways this can be seen as taking weakly-typed languages to a whole new level. Those who find Perl's sigils to be a bit odd in the first place probobly will not miss them much, but Perl programmers who have come to depend on them may feel a bit lost since in some ways all variables are scalars in PHP—they just scale to arrays and hashes as well as numbers and strings.

PHP refers to Perl's arrays and hashes as indexed arrays and associative arrays. However, PHP has only associative arrays since indexed arrays are just associtive arrays where the keys are numeric. The keys in PHP's associative arrays are ordered so that it can return elements in order. One way to think of PHP's indexed arrays is as a shorthand for creating associative arrays with ascending numeric keys. Table arrays compares Perl and PHP array and hash operations.

Array operations

PerlPHP
@x = (1,2,3);				
$x[3] = 4;				

\%x = ('a' => 1, 'b' => 2);
$x{'c'} = 3;				

push(@y,$x);				
$x = pop(@y);				
$x = shift(@y);			
unshift(@y,$x);			
@x = split/:/,$y;			
$y = join(':',@x);		
@x = @y[2,3,4];			
@x[2,3,4] = @y;
$x = Array(1,2,3);
$x[3] = 4;

$x = Array( 'a' => 1, 'b' => 2);
$x['c'] = 3;

array_push($y,$x);
$x = array_pop($y);
$x = array_shift($y);
array_unshift($y,$x);
$x = split('/:/', $y);
$y = join($x,':');
$x = array_slice($y,2,3);
array_splice($x,2,3,$y);

Perl has two very different data structures for working with indexed and associative arrays. The data structures are differentiated with the @ and \%, and accessed using the [] and \ notation rather than just the []. Perl uses the $ rather than the @ or % when indexing into an array or hash is that the result is a scalar since arrays and hashes contain only scalars. Perl programmers are familiar with the => notation that PHP uses to distinguish associative arrays from indexed arrays; however, they are probably not familiar with the Array() contruct, which is almost a type of constructor for both indexed and associative arrays.

Since PHP's arrays have iterator functions: current(), reset(), next(), each(), key(), prev(), and end(). While Perl has some implicit iterator functions for arrays and hashes they tend to work behind the scenes, and it is handy to have functions that work directly with the iterators. Perl 6 will boast arrays and hashes that are first class objects which can have methods such as PHP's iterating functions.

Control Structures

Perl and PHP have the usual control structures: if(), for(), while(), return(), and exit(). Both languages have a foreach() statement to iterate over arrays; however, their syntax and behavior are quite different given the different nature of arrays in each language. Table foreach shows the differences in syntax.

Syntax of foreach()

PerlPHP
foreach $x (@y) { }		
foreach $x (keys(%y)) { }	
foreach $x (@y) { $x++; }
foreach ($y as $x) { }		
foreach ($y as $k => $v) { }
foreach ($y as $x) { $x++; }

PHP uses the as keyword to indicate what sort of variable aliasing to use while iterating through the array. The two variants correspond to the types of arrays that PHP supports (indexed and associative). Perl's foreach() allows me to modify the aliased variable inside the body of my loop and have it modify the array or data structure that I am iterating over. The third example in Table foreach illustrates alias modification to increment each element in an array—this does not work under PHP.

PHP has a switch() statement. The absence of a switch() in Perl has been noted, and rationalized away since it is possible to use existing Perl syntax to do roughly the same thing. High on the list of new stuff for Perl6 is a super-charged switch() statement—which is so super and charged it isn't even called a switch().

Loop control is slightly different in PHP and Perl since PHP does not allow you to label blocks of code, and Perl's next() is equivalent to PHP's continue().

Loop comparisons

PerlPHP
LOOP1: while ($x) {			
    LOOP2: while ($y) {		
      next LOOP1 if $x == $y;
  }							
}
while ($x) {	
    while ($y) {	
      if ($x == $y) continue 2;
    }	
  }

Functionally Speaking

Perl and PHP allow me to extend the core language with user defined functions. PHP uses the function keyword and Perl uses sub to identify them. The function name is case sensitive in Perl, but not in PHP.

PHP allows me to declare parameters as part of the function definition. Supporting parameter definitions allows function parameters to take default values; and warnings are automatically thrown when I call a function with the incorrect number of parameters. Perl's functions give you access to the special array variable @_ which contains the function parameters, which I can copy or use directly. I can use function prototypes to validate the number and types of parameters that are passed to a Perl function; however, they will not work with methods in object-oriented Perl, which ignores prototypes. In Perl I have to explicitly validate the parameters and assign default values. Table area shows an area() function whose second parameter has the default value of one. In PHP the default value is part of the prototype, whereas in Perl I have to set it myself by checking the value of the second parameter explicitly.

Default function arguments

PerlPHP
sub area {			
    my ($x,$y) = @_;
    $y=1 if !$y;	
    $area = $x * $y;
    return($area);
}
function area ( $x, $y=1 ) {	
    $area = $x * $y;	
    return($area);
}

The area() function also illustrates the variable scoping rules in PHP and Perl. All variables in PHP functions are automatically lexically scoped, whereas variables in Perl's functions are automatically global. Like Perl, PHP functions can contain global variables—however I must declare them as global or they are undefined. On the other hand, PHP programmers who expect their Perl function variables to not interfere with global variables will be suprised when they do.

Function comparisons

PerlPHP
$x = 1;				
sub incrementX {
    $x++;			
}
$x = 1;	
function incrementX() {
    global $x;	
    $x++;
}

Unlike Perl, the lexical scoping of PHP variables is limited to function calls and as a result is often referred to as function-level scope. Perl allows me to define lexically-scoped variables in any block of code, including if-else statements and loop constructs. PHP also has the static variable type which allow variables to maintain their value between successive calls to a function, while making it invisible to outside code. In some ways PHP's static variables allow you to do things that you might do with closures in Perl.

References and Objects

Perl and PHP allow you to store references to other variables and functions in scalar variables, although they support references in very different ways. PHP uses the & to create a reference from a variable, while Perl uses the \ character. Perl requires you to dereference a reference using the appropriate sigil ($@%&) or the -> before you can use it; whereas PHP does not.

Array comparisons

PerlPHP
@x = (1,2,3,4,5);			
$y = \@x;					
print $x->[2];			

if (ref($y) eq 'SCALAR') {}
if (ref($y) eq 'ARRAY') {}
if (ref($y) eq 'HASH') {}	
if (ref($y) eq 'CODE') {}
$x = Array(1,2,3,4,5);	
$y = $x;					
print $y[2];				

if (is_scalar($x)) {}		
if (is_array($x)) {}		
if (is_array($x)) {}		
if (function_exists($x)) {}

Perl and PHP diverge quite a bit when it comes to defining and using object oriented features. In general PHP's syntax for declaring object classes is more explicit than Perl's syntax for declaring packages and modules which is far looser and reveals more of the internal details. Table circle shows a simple class for representing a circle, which has a method for calculating the area. Table use-circle shows code that uses the circle class.

Circle class

PerlPHP
    package Circle;				
	
    my $PI = 3.14159;			
    sub new {					
        my ($class,$r) = @_;	
        my $self = {			
            radius => $r		
        };                      
        bless $self, $class;	
        return($self);			
    }							
    							
    sub getArea {				
        my $self = shift;		
        my $r = $self->{radius};
        my $area = $PI * $r ** 2
        return($area);			
    }
class Circle {	                

var $radius;
var $PI = 3.14159;	
	                            
function Circle ( $r=0 ) {	
    $this->radius = $r;	    
}	                            
                  	
function getArea() {	        
    $area = $this->PI * pow($this->radius,2);
    return($area);                            
}


Using the Circle class

PerlPHP
use Circle;					
$circle = Circle->new(5);	
print $circle->getArea();
require("Circle.php");    
$circle = new Circle(5);  
print $circle->getArea();

PHP's constructors (simliar to Java) are the function with the same name as the class; PHP allows you to define the object attributes which are carried around automatically with objects of that type; PHP object attributes can be accessed using the special $this variable that refers to the object on which the method was called. Perl is extremely loose and allows any method to be a constructor, which must bless a variable into the appropriate package. Perl method calls have to remember that the first parameter passed to the method will be the object. The PHP class implementation is much more succinct and clear, and much of this is due to the ability to define object attributes and the use of the special $this variable. So much of Perl's object oriented features are learned conventions, and in some ways it can seem like a dark art for the beginning programmer. Perl's object-oriented features are much more flexible and extensible than PHP's. PHP does not support multiple inheritance, and the naming of modules in Perl allows you to build complex hierarchies of modules which are impossible in PHP. Perhaps this is why the CPAN has done so well, while extending PHP has been limited mainly to compiling components into the interpreter when you build it.

Perl and PHP together

Perl and PHP can be used together effectively in an organization. Consider a situation where a group of web designers carefully layout HTML and create graphics and flash animations on a website; while a group of programmers work to connect up this static content with a database to provide dynamic content. Although Perl modules like HTML::Mason and HTML::Template and Apache's embperl can provide solutions that would work as well, it is not difficult to imagine PHP being used to cater to both the designers and the programmers. Also imagine that the programmers would like to have something like CGI.pm's arsenal of exportable HTML functions that guarantee that HTML is well formed. Why not write a Perl program that writes the PHP library? No sooner said than done, or at least that's what Andy Lester did (who this code has been copied from).

The Perl program in code listing Perl to PHP generates a library of PHP functions (HTML.php) that I can use in other PHP applications that I want to have handy functions for generating HTML. I can automatically add tags by altering the @exports array. Not only is Perl a language that has borrowed from liberally from many languages, and had other languages borrow from it, but it turns out Perl is also a good PHP programmer.

About the author

Ed Summers is currently working as a programmer at Follett Library Resources in McHenry, Illinois.

Perl to PHP

#!/usr/bin/perl use strict; my @exports = qw( html head body title h1 h2 h3 h4 h5 h6 p br hr a small big font b i em strong pre kbd tt div span center nobr blockquote ul ol li tag_dl dt dd table tr td th form input select option textarea img ); my @empty_tags = qw( br hr input img ); my @lf_after = qw( table select tr td th p ); my @lf_between = qw( table select tr ); my @funcs; for my $func ( sort @exports ) { my $after = in_array( $func, @lf_after ) ? '."\n"' : ''; my $tag = uc $func; my $body; if ( in_array( $func, @empty_tags ) ) { $body = <<"PHP_CODE"; function $func( $parms = null ) { if ( isset($parms) ) { return "<$tag" . _build_parm_string( $parms ) . " />" $after; \ } else { return "<$tag />" $after; \ } } PHP_CODE } else { my $sep = in_array( $func, @lf_between ) ? '"\n"' : '" "'; $body = <<"PHP_CODE"; function $func() { $args = func_get_args(); return _nonempty_tag( '$tag', $sep, $args ) $after; } PHP_CODE } push( @funcs, $body ); } # Create HTML.php open( OUT, ">HTML.php" ) or die "Can't create"; print OUT "<?php\n"; print OUT "\n### DO NOT EDIT THIS FILE. IT IS CREATED BY HTML.pl.\n\n"; print OUT <DATA>; # Constant stuff print OUT join( "", @funcs ); print OUT "?>\n"; close OUT; sub in_array { my $needle = shift; my @haystack = @_; for ( @haystack ) { return 1 if $_ eq $needle; } return 0; } ## PHP CODE FOLLOWS __DATA__ function _nonempty_tag( $tagname, $sep, &$args ) { $return = '<' . $tagname; // If there's an Array(), it's our parms if ( $args && is_array($args[0]) ) { $return .= _build_parm_string( array_shift($args) ); } $return .= '>'; // At this point, everything else is text $first = true; foreach ( $args as $val ) { if ( is_array( $val ) ) { $val = implode( $sep, $val ); } if ( $first ) { $first = false; } else { $return .= $sep; } $return .= $val; } // while $return .= "</$tagname>"; return $return; } function _build_parm_string( &$parms ) { reset( $parms ); $str = ""; foreach ( $parms as $key => $val ) { $str .= ' '; $str .= $key; if ( isset($val) ) { $val = htmlspecialchars($val); $str .= "=\"$val\""; } } // foreach return $str; }