Perl and PHP are more different than alike. Let's consider Perl 5, since Perl 6 has become its own language (Raku), rather than a new version of Perl. Each language continues to evolve, so some items in this list may become out of date; readers should rely on official documentation to learn the current features of each language.
Perl has native regular expression support, including regexp literals. PHP uses Perl's regexp functions as an extension.
A number of language features are supported at the language level in PHP, but are implemented as packages in Perl (such as generators and some OOP operators). Some of these are mentioned below.
Both support escape sequences in strings, and support some of the same sequences, but Perl and PHP also have some different escape sequences for the same functionality (such as Unicode codepoints) and escapes sequences that they don't share at all.
Perl has quite a few more operators, including matching (=~
, !~
), quote-like (qw
, qx
&c.), string repetition (x
) and range (..
and ...
). PHP has a few operators Perl doesn't, such as the error suppression operator (@
), instanceof
and clone
(though Perl offers some of these via modules, such as Universal::isa
).
- Exponentiation (
**
) was not available in PHP before 5.6.
- The spaceship comparison operator (
<=>
) wasn't available in PHP until 7.0. In Perl, <=>
is for numeric comparison (cmp
for string); in PHP, it handles any comparable values.
In PHP, new
is an operator. In Perl, it's the conventional name of an object creation subroutine defined in packages, nothing special as far as the language is concerned.
Perl logical operators return their arguments, while they return booleans in PHP. Try:
$foo = '' || 'bar';
in each language. In Perl, you can even do $foo ||= 'default'
to set $foo
to a value if it's not already set.
PHP 7.0 added a NULL-coalescing operator ??
, and 7.4 added NULL-coalescing assignment ??=
. These are similar to, but more limited than, Perl's ||
, because they only return the right side if the left is NULL
, rather than any falsey value. Perl 5.10 added it's own NULL coalescing operator, //
. (Unrelated, '//' begins a single-line comment in PHP.)
Perl variable names indicate built-in type, of which Perl has three, and the type specifier is part of the name (called a "sigil"), so $foo
is a different variable than @foo
or %foo
.
(related to the previous point) Perl has separate symbol table entries for scalars, arrays, hashes, code, file/directory handles and formats. Each has its own namespace.
Perl gives access to the symbol table, though manipulating it isn't for the faint of heart. In PHP, symbol table manipulation is limited to creating references and the extract
function.
Note that "references" has a different meaning in PHP and Perl. In PHP, references are symbol table aliases. In Perl, references are smart pointers.
Perl has different types for integer-indexed collections (arrays) and string indexed collections (hashes). In PHP, they're the same type: an associative array/ordered map.
Perl arrays aren't sparse: setting an element with index larger than the current size of the array will create all intervening elements, though without initializing them (see perldata and exists
). PHP arrays are sparse; setting an element won't create intervening elements.
Perl supports hash and array slices natively, and slices are assignable, which has all sorts of uses. In PHP, you use array_slice
to extract a slice and array_splice
to assign to a slice.
Perl interpolates arrays into strings by joining all the elements with $"
. PHP interpolates arrays into strings by first converting the array to a string, which always results in the value "Array".
Perl automatically flattens lists (see perlsub); for un-flattened data structures, use references.
@foo = qw(bar baz);
@qux = ('qux', @foo, 'quux'); # @qux is an array containing 4 strings
@bam = ('bug-AWWK!', \@foo, 'fum'); # @bam contains 3 elements: two strings and a array ref
PHP added support for spreading in argument lists (called "argument unpacking") starting in 5.6, which must be done explicitly using ...
. In 7.4 a spread operator (under the moniker "array unpacking") was added, though only for integer indices. In 8.1 this operation was extended to string indices.
Before 7.4, PHP didn't allow underscores as digit separators in integer and floating point literals.
You can leave out the argument to the subscript operator in PHP for a bit of magic. In Perl, you can't leave out the subscript.
Perl hashes are unordered.
Perl has a large number of predefined and magic variables. PHP's predefined variables have quite a different purpose.
Perl has statement modifiers: some control statements can be placed at the end of a statement.
PHP added the match
expression in 8.0.
Perl supports dynamic scoping via the local
keyword.
In addition, Perl has global, lexical (block), and package scope. PHP has global, function, object, class and namespace scope.
In Perl, variables are global by default. In PHP, variables in functions are local by default.
Perl supports explicit tail calls via the goto
function.
Where PHP uses the more common parameter list to declare function arguments, Perl has prototypes.
- Prototypes are evaluated at compile time, and thus aren't checked in a number of situations (e.g. method calls).
- Prototypes offer more limited type checking for function arguments than PHP's type hinting. As a result, prototypes are of more limited utility than type hinting.
- The differing approaches to parameters affect related features, such as variadic functions, default parameter values and named parameters.
Perl uses pass-by-reference (even though array arguments are flattened in argument lists, the elements are passed by reference). Note that, due in part to the particular meaning of "reference" in Perl (mentioned above), "pass-by-reference" is used in the Perl documentation to mean something else ("passing a reference" would be more accurate) and is a way to avoid array and hash flattening in argument lists. PHP uses pass-by-value by default, though pass-by-reference can be explicitly specified for individual parameters and the variadic parameter, if used. Note the value of a variable storing an object is a handle to it, which means objects can still be mutated when passed by value, though the original variable itself cannot be altered to hold a different value.
When it comes to type hints, PHP offers various static typing features not in Perl: argument, variable, return (including some return-only) and nullable type declarations, and union (as of 8.0) and intersection (as of 8.1) type declarations. Most of these features have been added starting with 7.0.
In Perl, the last evaluated statement is returned as the value of a subroutine if the statement is an expression (i.e. it has a value), even if a return statement isn't used. If the last statement isn't an expression (i.e. doesn't have a value), such as a loop, the return value is unspecified (see perlsub). In PHP, if there's no explicit return, the return value is NULL.
Perl has special code blocks (BEGIN
, UNITCHECK
, CHECK
, INIT
and END
) that are executed. Unlike PHP's auto_prepend_file
and auto_append_file
, there is no limit to the number of each type of code block. Also, the code blocks are defined within the scripts, whereas the PHP options are set in the server and per-directory config files.
In Perl, the semicolon separates statements. In PHP, it terminates them, excepting that a PHP close tag ("?>") can also terminate a statement.
The value of expressions in Perl is context sensitive.
Negative subscripts in Perl are relative to the end of the array. $bam[-1]
is the final element of the array. Negative subscripts in PHP are subscripts like any other.
In Perl 5, classes are based on packages and look nothing like classes in PHP (or most other languages). Perl 6 classes are closer to PHP classes, but still quite different. (Perl 6 is different from Perl 5 in many other ways, but that's off topic.) Many of the differences between Perl 5 and PHP arise from the fact that most of the OO features are not built-in to Perl but based on hacks. For example, $obj->method(@args)
gets translated to something like (ref $obj)::method($obj, @args)
. Non-exhaustive list:
- PHP automatically provides the special variable
$this
in methods. Perl passes a reference to the object as the first argument to methods.
- Perl requires references to be blessed to create an object. Any reference can be blessed as an instance of a given class.
- In Perl, you can dynamically change inheritance via the packages
@ISA
variable.
- PHP supports anonymous classes as of 7.0.
Annotations (called "attributes" in both) are available in both starting with PHP 8.0, but are a language feature in PHP and a module in Perl.
PHP 8.1 added enums. While some Perl modules offer similar features, it doesn't have enums proper (nor are they as useful, given how types are handled).
Perl supports operator overloading.
Both use #
to begin single line comments, but PHP also uses //
(which is a NULL-coalescing operator in Perl, as previously mentioned).
Strictly speaking, Perl doesn't have multiline comments, but the POD system can be used for the same affect.
Until PHP 5.3, PHP had terrible support for anonymous functions (the create_function
function) and no support for closures.
PHP had nothing like Perl's packages until version 5.3, which introduced namespaces.
Perl creates package aliases by defining constants, storing them in variables, manipulating the symbol table or using a package that does one of these. PHP creates namespace aliases with use
.
Arguably, Perl's original built-in support for exceptions looks almost nothing like exceptions in other languages, so much so that they scarcely seem like exceptions. You evaluate a block and check the value of $@
(eval
instead of try
, die
instead of throw
). The TryCatch and Try::Tiny modules support exceptions as you find them in other languages (as well as some other modules listed in Error's See Also section). Perl 5.34.0 added the more standard try
/catch
syntax as an experiment, which is not enabled by default.
One interesting thing that has been happening is the languages have gotten more similar in a few ways, though this is not the result of either language influencing the other but rather new features that have been introduced into many modern programming languages.
My brain hurts now, so I'm going to stop.