PHP 8 elephant plushy

PHP 8: Idiosyncrasies, Oddities, Obscurities and Updates (Part 2): Statements, Blocks & Functions


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, or and xor. 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 >> 1 is equivalent to 6 / 2 while 6 >> 2 is equivalent to 6 / (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; and continue; 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 be 1, for the current loop only.)
  • for loops 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) ...
  • foreach loops use the as keyword: foreach ($arr as $item) and foreach ($assocArr as $key => $value) ...
  • Warning: In PHP, variables created within the parentheses of a foreach loop remain defined/in scope after the loop, unless unset () is called on them.
  • When performing comparison(s) on a variable, the cases of a switch statement do loose comparison.
  • Due to the way that a switch (conditionExpression) works (single evaluation of the condition), it is slightly more efficient than an if ... elseif ... if block, which evaluates each condition within it.
  • The match (conditionExpression) block (new in PHP 8) is similar to a switch (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 no default match. 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 a switch (condExpr) block. It is not intended to replace the switch (condExpr) block. (Each has a use case.)

Statements

  • Using the return statement 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: Using declare (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 goto statements 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 include and require statements 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, including void as 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 (makes null a permissible return value):
    function xy (int $arg): ?int { /* ... */ }
  • To specify multiple types for a parameter or return, separate them with pipes (|), although the mixed keyword 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 ...$args is 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 $needle and $haystack for the various search functions, for example.
  • PHP functions cannot use variables with global scope, unless prefixed with the global keyword:
    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 GLOBALS array (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 closure keyword.
  • 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 using date () and/or time() 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 as date_parse ($formattedDate), but allows for defining the format of the string representation of the date passed in.

To be continued with array functions ...

How do you rate this article?

5


Great White Snark
Great White Snark

I'm currently seeking fixed employment as a S/W & Web developer (C# & ASP .NET MVC, PHP 8+, Python 3), hoping to stash the farmed fiat and go full Crypto, quit the 07:30-18:00 grind. Unsigned music producer; snarky; white; balding; smashes Patriarchy.


Return to the Source
Return to the Source

Use the Force; read the source! This blog is mostly a collection of study notes on ASM, ASP .NET, Blender, BASIC, C/C++, C#, ChucK, Computer Architecture, Computer Literacy, CSS, Digital Logic, Electronics, F#, GIMP, GTK+, Haskel, Java, Julia, JavaScript (ES6+) & JSON, LISP, Nim, OOP, Photoshop, PLAD, Python, Qt, Ruby, Scheme, SQL (MySQL & SQLite), Super Collider, UML, Verilog, VHDL, WASM, XML. If I can learn it and make notes on it, I'll write about it. || Blog images copyright Markus Spiske and Pixabay

Publish0x

Send a $0.01 microtip in crypto to the author, and earn yourself as you read!

20% to author / 80% to me.
We pay the tips from our rewards pool.