What general tips do you have for golfing in PHP? I'm looking for ideas that can be applied to code golf problems in general that are at least somewhat specific to PHP (e.g. "remove comments" is not an answer). Please post one tip per answer.
-
\$\begingroup\$ Wait, am I doing it right?... Anyway, I'm really curious about this one. PHP is used by many people and golfers, but I almost have no idea how to golf a PHP code. \$\endgroup\$– JiminPJun 20, 2011 at 14:11
-
\$\begingroup\$ Use short tags <??> It can save a few bytes. \$\endgroup\$– MobAug 12, 2011 at 20:49
40 Answers
str_repeat
In some cases you have a input of characters and you should output them repeated with an input greater zero for each characters.
for(;--$z?:($c=$argn[$i++]).$z=$argn[$i++];)echo$c;
(52 bytes) is shorter than
for(;~$c=$argn[$i++];)echo str_repeat($c,$argn[$i++]);
or
for(;~$c=$argn[$i++];)echo str_pad($c,$argn[$i++],$c);
(54 bytes each)
How it works for example input a1b2c1
$z
is not set (implicit NULL
), so --$z
does nothing and is falsy;
$c="a"
, $z="1"
and $i=2
-> $c.$z="a1"
is truthy -> output "a"
--$z=0
; so we set $c="b"
, $z="2"
(and $i=4
) -> $c.$z="b2"
is truthy -> output "ab"
--$z=1
-> output "abb"
--$z=0
; so we set $c="c"
and $z=1
$c.$z="c1"
is true output "abbc"
--$z=0
so $c=""
and $z=""
-> $c.$z=""
is falsy -> loop breaks
Removing characters in a string
join(explode(" ",$string));
saves 1 character compared to
str_replace(" ","",$string);
-
\$\begingroup\$ Note that this works for all (nonempty) strings, not just characters. \$\endgroup\$ Jun 23, 2017 at 16:58
-
\$\begingroup\$ @CalculatorFeline Why should it not work for empty strings? It make no sense or this case. \$\endgroup\$ Jun 23, 2017 at 17:02
-
\$\begingroup\$ Well, the first version doesn't work with
""
and it's not very useful anyway. \$\endgroup\$ Jun 23, 2017 at 17:04 -
1\$\begingroup\$ @CalculatorFeline And for this case a zero byte solution is much better. It make no sense to do this in that way. \$\endgroup\$ Jun 23, 2017 at 17:17
-
3\$\begingroup\$ Your join example is missing a
)
. Andstrtr($string,[" "=>""])
is even shorter. \$\endgroup\$– TitusOct 10, 2017 at 8:23
use deprecated functions
If you can use POSIX instead of PERL regex without wasting more than 5 bytes on the expression, use ereg
or eregi
instead of preg_match
, split
or spliti
instead of preg_split.
split
Can also be used as a synonym for explode
for most delimiters.
These functions are marked deprecated and will throw E_DEPRECATED
notices, but (cannot find the source now) I think I have read that warnings and notices are ok.
-
2\$\begingroup\$ Watch out! These were removed in PHP 7.0. \$\endgroup\$– UmbrellaSep 7, 2018 at 18:34
Use short append syntax to add elements to the end of an array.
Instead of keeping track of the number of elements:
$array[++$i] = $value;
Or using the explicit push function:
array_push($array, $value);
You can use the implicit push feature:
$array[] = $value;
-
1\$\begingroup\$ With a rare exception: when you need to append more than 3 elements,
array_push($array, $value, $value, $value, $value);
may be shorter; \$\endgroup\$ Jan 5, 2017 at 19:37 -
\$\begingroup\$ Heh yeah, also note, if
$value
is itself an array, it's probably not going to do what you want. \$\endgroup\$ Jan 5, 2017 at 19:42
JSON encode static array definitions
JSON encoding is one byte shorter per element than native PHP encoding for associative arrays. Of course, then you have to quote the resulting string (an additional two chars) and call json_decode()
on that string (an additional 13 chars.) So, if you have a static associative array with more than 15 elements, try JSON encoding it. Note this probably won't work if you can use the "unquoted string literals" trick in your PHP array definition.
Instead of:
$array = [...];
Use:
$array = json_decode('...');
-
1
Switches base on arrays or strings
A little collection which can save Bytes for different conditions
Switch a function through an array
<?=(bc.[sub,add,mul,pow][($x=$argn)&3])($x,$x);
Make different Math operations
<?=[0,($x=$argn)+$x,$x*$x,$x**$x][$x&3];
Ternary Operator to switch a function
echo(strto.(rand()&1?low:upp).er)($c);
Using the Keys in an array as conditions
echo[ctype_alpha($s=dechex($argn))=>"Only letters",ctype_digit($s)=>"Only numbers",Mix][1];
special on strings but only not in all cases you must use a function and trim
will do nothing
($bool?trim:strtolower)($string)
character switch
"char"[$x%4]
character only in zero cases
"c"[$x%2]
I didn't see it listed so when using a list and explode you can use a number as the delimiter ( assuming its not in the string of course ). This lets you get rid of the quotes.
If there is backslash before the delimiter then it has to be 8
or 9
so it doesn't get confused with octal ( such as \0
)
So instead of:
explode(",", "one,two,buckle,my,shoe")
You can do this
explode(1, "one1two1buckle1my1shoe")
Saving 2 bytes for the quotes.
As I mentioned for backslashes
explode(",", "/ \,| .. |,\ /");
Use 8
or 9
explode(8, "/ \8| .. |8\ /"); // so you get \8 instead of \0 etc..
seek potential in combining several expressions to one
It´s easy to see that A?B:C;
is shorter than if(A)B;else C;
A&&B
is shorter than if(A)B;
and A||B;
is shorter than if(!A)B;
But how can if(A){B;C;}else{D;E;}
be golfed?
Assume that B
returns something truthy and D
something falsy:
if(A){B; C;}else{B; C;} # 21 bytes
A? B&&C : B||C; # 12 bytes
another one:
if(A){$b=123;$c="hello";} # 25 bytes
A&&$b=123+!$c="hello": # 22 bytes
A&&$c="hello".!$b=123; # also 22 bytes
$c="hello
is truthy, so !$c
is false
. +
casts to int; so we add 0
to 123
.
$b=123
is truthy, so !$b
is false
. .
casts to string, and that´s empty for false
.
I even had a case today where appending digits to the string didn´t make a difference.
(See line 5 of the breakdown.)
more examples:
for(;;$a++,print$x);
for(;;$a+=print$x);
print
always returns true, so its return value can be added to $a
instead of incrementing $a
separately.
$a=1,$b=0
$a=!$b=0
if(X){$a=123;$b=0;}
X&&$a=123+$b=0; # useful if you need $b to be and int (for printing)
X&&$b=!$a=123;
if(X){$a=123;$b=1;}
X&&$b=!!$a=123;
X&&$a=123*$b=1;
advanced: combining nested loops
takes a new level to combining expressions. There is no general solution or approach; and it doesn´t always make the code shorter. Good chances are when the outer loop has no body except the inner loop; imagine shifting through a 2D array or sorting one.
Try
for($a=1;$a<20;$a+=print"\n")for($b=$a;$b++<20;)echo$a*$b,"\t";
61 bytes (counting the control characters as one each)
that loop $a
from 1
to 19
, $b
from $a+1
to 20
and print the products, breaking the line when $a
increments.
Ok, one simple two-byte saving is
for($a=1;20>$b=$a;$a+=print"\n")for(;$b++<20;)echo$a*$b,"\t";
Combining the two loops to one saves another two bytes:
for($a=$b=1;$b++<20||21>$b=1+$a+=print"\n";)echo$a*$b,"\t";
And you can save two more bytes with a leading linebreak instead of a trailing one (this often saves a byte or two):
for($b=20;$b++<20||21>$b=1+$a+=print"\n";)echo$a*$b,"\t";
This is a pretty easy and rewarding example; so don´t be upset if your first attempts fail on saving bytes. It may take a while until you get an eye for it.
Ok, for(;20>$b=++$a;print"\n")for(;$b++<20;)echo$a*$b,"\t";
is golfier; and in PHP 7, you can even avoid trailing tabs without any costs: for(;20>$b=++$a;)for(;$b++<20;)echo$a*$b,"\n\t"[$b<20];
But imagine you have to loop $a
from somewhere else but 1
, like through ascii codes.
I may one day come up with an example that makes more sense. No promises on these premises though.
-
\$\begingroup\$ primo also posted on combining loops in March 2014. Don´t miss out on that one! \$\endgroup\$– TitusFeb 22, 2019 at 15:26
When using array_values()
to re-index an array with numeric keys, from PHP7.4 you can use a technique that I call splatpacking (see link for further details and a demonstration).
You use the "splat/spread" operator to "unpack" the array, then immediately "repack" the elements into an empty array. Though not designed for this purpose, the result is the same -- in that limited scenario.
Technique using $a
representing an array:
array_values($a) // 14 characters (not counting $a)
becomes
[...$a] // 5 characters (not counting $a)
Little-known tricks with increment/decrement
$x = 'a';
echo ++$x; // Outputs "b"
$x = 'z';
echo ++$x; // Outputs "aa"
And many more at the following RFC, showing they will be removed/normalized in PHP 8.3