Perl is used plenty for websites, no less than Python and Ruby for example. That said, PHP is used way more often than any of those. I think the most important factors in that are PHP's ease of deployment and the ease to start with it.
The differences in syntax are too many to sum up here, but generally it is true that it has more ways to express yourself (this is know as TIMTWOTDI, There Is More Than One Way To Do It).
I've noticed that most PHP vs. Perl pages seem to be of the
PHP is better than Perl because
<insert lame reason here>
ilk, and rarely make reasonable comparisons.
Syntax-wise, you will find PHP is often easier to understand than Perl, particularly when you have little experience. For example, trimming a string of leading and trailing whitespace in PHP is simply
$string = trim($string);
In Perl it is the somewhat more cryptic
$string =~ s/^\s+//;
$string =~ s/\s+$//;
(I believe this is slightly more efficient than a single line capture and replace, and also a little more understandable.) However, even though PHP is often more English-like, it sometimes still shows its roots as a wrapper for low level C, for example, strpbrk and strspn are probably rarely used, because most PHP dabblers write their own equivalent functions for anything too esoteric, rather than spending time exploring the manual. I also wonder about programmers for whom English is a second language, as everybody is on equal footing with things such as Perl, having to learn it from scratch.
I have already mentioned the manual. PHP has a fine online manual, and unfortunately it needs it. I still refer to it from time to time for things that should be simple, such as order of parameters or function naming convention. With Perl, you will probably find you are referring to the manual a lot as you get started and then one day you will have an a-ha moment and never need it again. Well, at least not until you're more advanced and realize that not only is there more than one way, there is probably a better way, somebody else has probably already done it that better way, and perhaps you should just visit CPAN.
Perl does have a lot more options and ways to express things. This is not necessarily a good thing, although it allows code to be more readable if used wisely and at least one of the ways you are likely to be familiar with. There are certain styles and idioms that you will find yourself falling into, and I can heartily recommend reading Perl Best Practices
(sooner rather than later), along with Perl Cookbook, Second Edition
to get up to speed on solving common problems.
I believe the reason Perl is used less often in shared hosting environments is that historically the perceived slowness of CGI and hosts' unwillingness to install mod_perl due to security and configuration issues has made PHP a more attractive option. The cycle then continued, more people learned to use PHP because more hosts offered it, and more hosts offered it because that's what people wanted to use. The speed differences and security issues are rendered moot by FastCGI these days, and in most cases PHP is run out of FastCGI as well, rather than leaving it in the core of the web server.
Whether or not this is the case or there are other reasons, PHP became popular and a myriad of applications have been written in it. For the majority of people who just want an entry-level website with a simple blog or photo gallery, PHP is all they need so that's what the hosts promote. There should be nothing stopping you from using Perl (or anything else you choose) if you want.
At an enterprise level, I doubt you would find too much PHP in production (and please, no-one point at Facebook as a counter-example, I said enterprise level).
My favorite thing about Perl is the way it handles arrays/lists. Here's an example of how you would make and use a Perl function (or "subroutine"), which makes use of this for arguments:
sub multiply
{
my ($arg1, $arg2) = @_; # @_ is the array of arguments
return $arg1 * $arg2;
}
In PHP you could do a similar thing with list(), but it's not quite the same; in Perl lists and arrays are actually treated the same (usually). You can also do things like:
And another difference that you MUST know about, is numerical/string comparison operators. In Perl, if you use <, >, ==, !=, <=>, and so on, Perl converts both operands to numbers. If you want to convert as strings instead, you have to use lt, gt, eq, ne, cmp (the respective equivalents of the operators listed previously). Examples where this will really get you:
if ("a" == "b") { ... } # This is true.
if ("a" == 0) { ... } # This is also true, for the same reason.
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.
Some differences, grouped roughly by subject:
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 !~1, including !~2 (=~, !~), !~3 (qw, qx &c.), !~4 (x) and !~5 (.. and ...). PHP has a few operators Perl doesn't, such as the !~6 (@), !~7 and !~8 (though Perl offers some of these via modules, such as !~9).
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 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.
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.
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 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).
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 eval0 section). Perl 5.34.0 added the more standard eval1 syntax as an eval2, 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.
PHP was inspired by Perl the same way Phantom of the Paradise was inspired by Phantom of the Opera, or Strange Brew was inspired by Hamlet. It's best to put the behavior specifics of PHP out of your mind when learning Perl, else you'll get tripped up.