PHP Advanced Concepts

summary: Going through some php advanced concepts like magic methods, variable variable, variadic functions, anonymous functions, dependency injection…

Some Advanced Concept

Magic Methods

Magic Methods are fall-through methods that get called whenever you invoke a method that doesn’t exist or assign or read a property that doesn’t exist, among other things.

interface AllMagicMethods {
    // accessing undefined or invisible (e.g. private) properties
    public function __get($fieldName);
    public function __set($fieldName, $value);
    public function __isset($fieldName);
    public function __unset($fieldName);

    // calling undefined or invisible (e.g. private) methods
    public function __call($funcName, $args);
    public static function __callStatic($funcName, $args); // as of PHP 5.3

    // on serialize() / unserialize()
    public function __sleep();
    public function __wakeup();

    // conversion to string (e.g. with (string) $obj, echo $obj, strlen($obj), ...)
    public function __toString();

    // calling the object like a function (e.g. $obj($arg, $arg2))
    public function __invoke($arguments, $...);

    // called on var_export()
    public static function __set_state($array);
}

Variable Variables

Variable variables are really powerful you create a variables dynamically use them dynamically and also it works with functions.

$foo = 'bar';
$bar = 'foobar';
echo $$foo;    //This outputs foobar

function bar() {
    echo 'Hello world!';
}

function foobar() {
    echo 'What a wonderful world!';
}
$foo();    //This outputs Hello world!
$$foo();    //This outputs What a wonderful world!

Variadic Functions

functions with a undefined number of arguments using the func_get_args().

<?php

function test() {

    $args = func_get_args();
    echo $args[2]; // will print 'd'
    echo $args[1]; // will print 3
}

test(1,3,'d',4);

?>

ref: https://stackoverflow.com/questions/61401/hidden-features-of-php

Anonymous Functions

Anonymous functions, also known as closures, allow the creation of functions which have no specified name. They are most useful as the value of callable parameters, but they have many other uses.

Anonymous functions are implemented using the Closure class.

<?php
echo preg_replace_callback('~-([a-z])~', function ($match) {
return strtoupper($match[1]);
}, 'hello-world');
// outputs helloWorld
?>

Dependency Injection

Makes code testing and refactoring easier

class StoreService {
    private $geolocationService;

    public function __construct(GeolocationService $geolocationService) {
        $this->geolocationService = $geolocationService;
    }

    public function getStoreCoordinates($store) {
        return $this->geolocationService->getCoordinatesFromAddress($store->getAddress());
    }
}

And the services are defined using an interface:

interface GeolocationService {
    public function getCoordinatesFromAddress($address);
}

class GoogleMaps implements GeolocationService { ...

class OpenStreetMap implements GeolocationService { ...

Now, it is for the user of the StoreService to decide which implementation to use. And it can be changed anytime, without having to rewrite the StoreService.

The StoreService is no longer tightly coupled to its dependency.

Magic Methods

1. __construct()

  • Purpose: The constructor method. It is called when an object is created.
  • Example:phpCopy codeclass MyClass { public function __construct() { echo "Object created!"; } } $obj = new MyClass(); // Outputs "Object created!"

2. __destruct()

  • Purpose: The destructor method. It is called when an object is destroyed.
  • Example:phpCopy codeclass MyClass { public function __destruct() { echo "Object destroyed!"; } } $obj = new MyClass(); unset($obj); // Outputs "Object destroyed!"

3. __call()

  • Purpose: Handles calls to undefined or inaccessible methods in an object context.
  • Example:phpCopy codeclass MyClass { public function __call($name, $arguments) { echo "Calling method '$name' with arguments: " . implode(', ', $arguments); } } $obj = new MyClass(); $obj->nonExistentMethod('arg1', 'arg2'); // Outputs "Calling method 'nonExistentMethod' with arguments: arg1, arg2"

4. __callStatic()

  • Purpose: Handles calls to undefined or inaccessible methods in a static context.
  • Example:phpCopy codeclass MyClass { public static function __callStatic($name, $arguments) { echo "Calling static method '$name' with arguments: " . implode(', ', $arguments); } } MyClass::nonExistentStaticMethod('arg1', 'arg2'); // Outputs "Calling static method 'nonExistentStaticMethod' with arguments: arg1, arg2"

5. __get()

  • Purpose: Handles reading of undefined or inaccessible properties.
  • Example:phpCopy codeclass MyClass { public function __get($name) { return "Getting the value of '$name'"; } } $obj = new MyClass(); echo $obj->nonExistentProperty; // Outputs "Getting the value of 'nonExistentProperty'"

6. __set()

  • Purpose: Handles writing to undefined or inaccessible properties.
  • Example:phpCopy codeclass MyClass { public function __set($name, $value) { echo "Setting '$name' to '$value'"; } } $obj = new MyClass(); $obj->nonExistentProperty = 'value'; // Outputs "Setting 'nonExistentProperty' to 'value'"

ref: https://www.php.net/manual/en/language.oop5.magic.php , https://wpwebinfotech.com/blog/advanced-php-concepts/

Clean Code

Use explanatory variables

Bad:

$address = 'One Infinite Loop, Cupertino 95014';
$cityZipCodeRegex = '/^[^,]+,\s*(.+?)\s*(\d{5})$/';
preg_match($cityZipCodeRegex, $address, $matches);

saveCityZipCode($matches[1], $matches[2]);

Not bad:

It’s better, but we are still heavily dependent on regex.

$address = 'One Infinite Loop, Cupertino 95014';
$cityZipCodeRegex = '/^[^,]+,\s*(.+?)\s*(\d{5})$/';
preg_match($cityZipCodeRegex, $address, $matches);

[, $city, $zipCode] = $matches;
saveCityZipCode($city, $zipCode);

Good:

Decrease dependence on regex by naming subpatterns.

$address = 'One Infinite Loop, Cupertino 95014';<br>$cityZipCodeRegex = '/^[^,]+,\s*(?<city>.+?)\s*(?<zipCode>\d{5})$/';<br>preg_match($cityZipCodeRegex, $address, $matches);<br><br>saveCityZipCode($matches['city'], $matches['zipCode']);

Avoid Mental Mapping

Don’t force the reader of your code to translate what the variable means. Explicit is better than implicit.

Bad:

$l = ['Austin', 'New York', 'San Francisco'];

for ($i = 0; $i < count($l); $i++) {
    $li = $l[$i];
    doStuff();
    doSomeOtherStuff();
    // ...
    // ...
    // ...
    // Wait, what is `$li` for again?
    dispatch($li);
}

Good:

$locations = ['Austin', 'New York', 'San Francisco'];

foreach ($locations as $location) {
    doStuff();
    doSomeOtherStuff();
    // ...
    // ...
    // ...
    dispatch($location);
}

Avoid negative conditionals

Bad:

function isDOMNodeNotPresent(DOMNode $node): bool
{
    // ...
}

if (! isDOMNodeNotPresent($node)) {
    // ...
}

Good:

function isDOMNodePresent(DOMNode $node): bool
{
    // ...
}

if (isDOMNodePresent($node)) {
    // ...
}

Namespace

Difference between __NAMESPACE__ and keyword ‘namespace’ that I find relevant is when invoking a class:

<?php
namespace MyApp;
class App {
  static function app(){
    echo 'hello app';
  }
}
// this will work:
$obj = new namespace\App::app();
// this will not work
$obj = new __NAMESPACE__\App::app();
// however this will work:
$obj = __NAMESPACE__ . '\App';
$obj::foo();
?>

Namespace name definitionsUnqualified name. This is an identifier without a namespace separator, such as FooQualified name. This is an identifier with a namespace separator, such as Foo\BarFully qualified name

This is an identifier with a namespace separator that begins with a namespace separator, such as \Foo\Bar. The namespace \Foo is also a fully qualified name.Relative name. This is an identifier starting with namespace, such as namespace\Foo\Bar.

«
»

Leave a Reply

Your email address will not be published. Required fields are marked *