This post is part two of many. It picks up where Part 1 left off.
Operands and Operators (Continued)
- PHP 8 has keyword operators that provide alternatives for
&&, ||and^:and, orandxor. However, the keywords have lower operator precedence than their symbol counterparts. For this reason, it is advised to always use parentheses with them, to make comparisons explicit. - PHP's logical operators are short-circuiting. (There is no guarantee that both sides are evaluated in a comparison. As soon as the required condition is voided or can complete, evaluation completes.)
- The left shift (
<<) operator multiplies a value by two, but the right shift (>>) operator divides by two.6 >> 1is equivalent to6 / 2while6 >> 2is equivalent to6 / (2 ** 2) - Using the addition (
+) operator with arrays on either side of it causes values with the same indices in the second array to overwrite those in the first array.['a' => 1, 'b' => 2] + ['a' => 4, 'c' => 6]results in['a' => 4, 'b' => 2, 'c' => 6] - The execution operator is used by placing backticks (
``) around code. It allows for executing shell commands from within PHP.
Conditional Blocks and Loops
- For
if ... elseif ... else ...and loop (for, while) blocks, PHP has alternative syntax to using braces:
<?php if ($grade >= 95): ?> <strong>A+</strong> <?php elseif (score >= 90): ?> <strong>A</strong> <?php /* ... More tests and HTML output here */ ?> <?php else { echo 'F'; } ?> - The
break;andcontinue;statements can be followed by an integer literal, which indicates out of how many loop levels to break or skip:break 2;will break out of both the current loop and the prior one. (If a number is not given, it is assumed to be1, for the current loop only.) forloops can have multiple expressions in each part of what's contained in their parentheses. Expressions must be separated by commas:for ($i = 0, $j = 2; i < $x, $j %2 == 0; i++, j += 2) ...foreachloops use theaskeyword:foreach ($arr as $item)andforeach ($assocArr as $key => $value) ...- Warning: In PHP, variables created within the parentheses of a
foreachloop remain defined/in scope after the loop, unlessunset ()is called on them. - When performing comparison(s) on a variable, the cases of a
switchstatement do loose comparison. - Due to the way that a
switch (conditionExpression)works (single evaluation of the condition), it is slightly more efficient than anif ... elseif ... ifblock, which evaluates each condition within it. - The
match (conditionExpression)block (new in PHP 8) is similar to aswitch (conditionExpression)block, but it has different syntax and structure:
<?php $result0 = match (CondExpr) { $caseLiteral0 => operationExpr0, $caseLiteral1 => operationExpr1 /*, ... */ }; $result1 = match ($paymentStatus) { 1 => print ('Paid'), 2, 3 => print ('Declined'), // seperate multiple matches with commas 0 => print ('Pending') }; - Unlike a
switch (condExpr)block, the match (condExpr) does not fall through cases and has nodefaultmatch. It also does strict comparison. It can also execute only one expression/statement per match. To execute multiple expressions, call a function or change to aswitch (condExpr)block. It is not intended to replace theswitch (condExpr)block. (Each has a use case.)
Statements
- Using the
returnstatement in a global scope will stop execution of the current script file. - The
declare (arg = val)statement/function can be used for three things:
1.ticks: A tick is similar to an event and is caused by statement execution (but not all statements are tickable).delare (ticks = intLiteral)tells PHP how many ticks should pass before the registered tick function runs. I'm not sure what practical purpose this serves and it's unlikely you'll ever encounter this.
2.encoding: Usingdeclare (encoding = 'utf-8')set's the script file's character encoding to UTF-8. It is advised that this declaration not be used.
3. strict_types: As mentioned in Part 1,declare (strict_types = 1)makes PHP code strongly-typed. However, this needs to be at the top of all the files in a project, since it only applies to the current file. - PHP supports
gotostatements and labels. However, since the use of these is considered harmful due to their resulting in spaghetti code, their use is discouraged. - The best use for the
includeandrequirestatements is importing global constants and functions (including chunks of HTML to output, such as navigation menus). - To include the contents of a file into a string variable, place
ob_start ();before the include statement and$val = ob_get_clean ();after it. This is potentially useful for doing string manipulation (such as replacement to shorten link text for mobile views of content).
Functions
- Functions can be called prior to being declared in a file, provided that their declaration is not conditional. It is best practice, however, to declare them before using them. (It makes code easier to maintain and understand.)
- In PHP, functions can be declared within the bodies of other functions. In order to use them, the outer function must be called first, since the inner function will only be defined when the outer function executes. For this reason, such practice is not recommended. (It makes code difficult to read and follow, thus potentially introducing bugs.)
- PHP 8 allows type-hinting for both function parameters and return types:
function xy (type $x, type $y): type { /* ... */}(where 'type' is a datatype, includingvoidas the return type) - PHP will do automatic datatype conversion where possible, if strict typing is not in effect/enforced.
- Prefixing a type hint for the return with a question mark (
?type) makes it nullable (makesnulla permissible return value):function xy (int $arg): ?int { /* ... */ } - To specify multiple types for a parameter or return, separate them with pipes (
|), although themixedkeyword will also work if you don't want to be explicit:function fx (int|float $x): int|float { /* ... */} - Function parameters can be given default values:
function fx (int $x, int $y = 0) { return $x * $y; } - To pass a parameter/argument by reference (instead of value), use an ampersand (
&) before the dollar sign ($):function fx (&$varByRef) { /* ... */ } - Variadic functions (such as
print ()) accept any number of arguments. They are defined as follows:
function fx (datatype $arg0, datatype $arg1, datatype ...$args): returnType { /* $arg0 and $arg1 are optional, depending on the function; * ...$args is what allows for multiple arguments, since it is an array. */ } - For variadic functions, type-hinting will not work if
...$argsis replaced by an array when the function is declared or called. - If an associative array is passed as
...$args, the keys will be treated as the parameter names. (See the point about named arguments below.) - PHP 8 functions also support named arguments (specifying arguments in any order when called). This is great news for anyone who can't remember the correct order of
$needleand$haystackfor the various search functions, for example. - PHP functions cannot use variables with global scope, unless prefixed with the
globalkeyword:
var $x = 0; function fx () { // $x is not in scope here. Declaring $x will create shadow with local/function scope global $x; // global $x is now in scope. Equivalent to passing $x by reference (&$x) } - Global variables can be accessed from the
GLOBALSarray (a superglobal), using the variable's name as the key:$localX = GLOBALS['x'] - Variables in functions can be made static by placing the static keyword in front of them: function
fx () { static $x = 0; /* ... */ } - Like JavaScript, PHP supports variable functions, callable by appending parentheses to String variables. When PHP detects parentheses after a variable, it will look for and execute a function with the same name as the evaluated string value of that variable.
$funcName = "sum"; $res = $funcName (2, 4); // calls sum (2,4), if the sum function exists; - To check if a variable's value evaluates to the name of a callable function, use the
is_callable ($var)function in a conditional (if) block.
Anonymous/Lambda & Arrow Functions
- PHP supports anonymous/lambda functions. They have to end in semicolons and be associated with variables or be passed as arguments to other functions that make use of callbacks. (Functions may also return callback functions.)
$fx0 = function (int|float ...numbers): int|float { /* ... */ } $fx1 = function (int|float $x, int|float $y) use ($x): int|float { /* ... */ } - When passing a function as an argument, it will be used as a callback function. PHP has a number of built-in functions that require making use of a callback function. For example, the
array_map (callback function ($element) { /* operation for each element */}, $array)function. This can also be expressed as follows:
$callback = function ($element) { /* ... operation */ }; $arrOut0 = array_map ($callback, $arr); function cb ($element) { /* ... */ } $arrOut1 = array_map ('cb', $arr); $sum = function (callable $summer, int|float ...$numbers) { /* Add numbers here */ return $summer ($numbers); // summer is a function that does a sum } echo sum ('summer', 1, 2, 3, 8, 17); - Anonymous functions are instances of closures, which will be covered later. They can be type-hinted with the
closurekeyword. - Callable/callbacks can be closures or named functions, but closures can only be anonymous functions.
- Arrow functions were introduced in PHP 7.4. They are a type of anonymous/lambda function, but can only be passed as arguments and are always defined with
fn. In an arrow function, the body is always a single statement after a fat arrow (=>):
// return $arg * $arg for each element of $arr0 $arr1 = array_map (fn ($arg) => $arg * $arg, $arr0); - Arrow functions can access variables from the parent scope, including global scope, but only by value.
Procedural PHP has plenty of built-in functions. To avoid making this section too long, I'm going to put functions relating to arrays (of which there are many, since a lot of PHP deals with arrays) in another part/post.
Date, Time and Time Zone Functions
For some reason, I always have difficulty remembering how to work with dates, times and time zones in PHP (hence why this section is rather detailed).
- To get the current UNIX timestamp in seconds, use the
time ()function. - To get a formatted date, use the
date ($formatStr, $tsSeconds)function. - To override the time zone set by PHP's configuration (php.ini), and used by PHP's date and time functions, use the
date_default_timezone_set ($tzStr)function prior to usingdate ()and/ortime()functions. - To show the time zone being used by PHP, use the
date_default_timezone_get ()function. - The
mktime ()function will give you a UNIX timezone based on the arguments you pass (day, month, year, hour, etc.):
$ts = mktime (hour: 1, minute: 0, second: 0, month: 4, day: 10, year: 1989); // this can be passed to date ($formatStr, $ts) - The strtotime
($formattedDateStr)function will convert a string representation of a date and/or time to a UNIX timestamp. It can also be passed a relative date and/or time (such as 'yesterday', 'last day of June 2019' or 'first Friday of October 2016'). - The
date_parse ($formattedDateStr)function returns an associative array containing components of a date (year, month, day, hour, minute, second, fraction). - The
date_parse_from_format ($format, $formattedDate)function results in the same output asdate_parse ($formattedDate), but allows for defining the format of the string representation of the date passed in.
To be continued with array functions ...