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 code
class 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 code
class 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 code
class 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 code
class 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 code
class 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 code
class 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 Foo
Qualified name. This is an identifier with a namespace separator, such as Foo\Bar
Fully 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