PHP Language Revision of Fundamentals Martin Kruliš by Martin Kruliš (v2.0) 28. 2. 2019
Revision of PHP Fundamentals Basic Syntax C-like syntax with relicts from Perl Specialties and differences foreach – iteration over structures String concatenation $str1 . $str2 Equality == vs identity === comparison Spaceship operator $a <=> $b Returns -1, 0, or 1 if $a is lesser, equal, or greater $b Null coalescing operator $a ?? $b Returns first operand if exists and not null, otherwise returns second operand by Martin Kruliš (v2.0) 28. 2. 2019
Revision of PHP Fundamentals Dynamic Nature of PHP Values Exist in a managed memory space Created as literals, results of expressions, or by internal constructions and functions Explicit data types, but weak typing boolean, integer, float, string, array, object, resource, null Memory Management Uses copy-on-write and reference counting Values are not always copied on assignment Once a value has zero references, it is garbage collected To my best knowledge, PHP does not employ more elaborate means of garbage collecting. The scripts are expected to run only for a short time (handle one HTTP request) and the reference counting works fine unless cyclic references are created. by Martin Kruliš (v2.0) 28. 2. 2019
Revision of PHP Fundamentals Dynamic Nature of PHP Variables Mnemonic references to values No declarations, created on the first assignment In the global or local scope Globals can be mapped into local context (global keyword) No explicit type (type is determined by current value) Type can be changed with a new assignment Existence can be tested (isset) and terminated (unset) Arrays An array item behaves in many ways like a variable There are very few good applications for global keyword. Use it carefully. Furthermore, note that the global keyword enforces explicit mapping of external (global) variables into local scope, which promotes the idea of writing more coherent functions (i.e., functions that depend only on data passed by arguments). by Martin Kruliš (v2.0) 28. 2. 2019
Revision of PHP Fundamentals Strings and Text Processing Preprocessed string literals "We have $fooCount foos.\n" PHP have a huge arsenal of string functions strlen(), substr(), trim(), explode(), join(), … Libs for charset manipulation Multibyte string lib, Iconv lib, Recode Functions for typical cases urlencode(), htmlspecialchars(), … Regular expressions preg_match(), preg_replace(), preg_split() by Martin Kruliš (v2.0) 28. 2. 2019
Revision of PHP Fundamentals Arrays Array in PHP is an ordered map of key-value pairs Can be used as array, list, hash table, dictionary, stack/queue, multi-dimensional array, or tree Defining arrays – array language construct $a1 = array(1, 2, 3); $a1 = [1, 2, 3]; $a2 = array('foo' => 42, 'bar' => 54); Accessing elements echo $a1[1] + $a2['foo']; $a2['spam'] = 19; $a1[] = 4; unset($a1[2]); Each element may have different type Prints ’44’ Note that unset($a1[2]); does not compact the array; The following key is assigned $a1 ~ [0=>1, 1=>2, 3=>4] by Martin Kruliš (v2.0) 28. 2. 2019
Variable Variables Indirect Access to Values Name of one variable is stored in another variable $a = 'b'; $$a = 42; // the same as $b = 42; $a = 'b'; $b = 'c'; $c = 'd'; $$$$a = 'hello'; // the same as $d = 'hello'; The {,} can be used to avoid ambiguous situations Can be used with members, functions, classes, … $obj = new $className(); $obj->$varName = 42; by Martin Kruliš (v2.0) 28. 2. 2019
References References $a int (2) int (1) $b Similar to Unix hard-links in FS Multiple variables attached to the same data Reference is taken by the & operator Independent on object references A reference to an object can be created $a = 1; $b = &$a; $b++; echo $a; // prints 2 $a int (2) int (1) $b by Martin Kruliš (v2.0) 28. 2. 2019
References in Functions Arguments as References Similar usage as var keyword in Pascal function inc(&$x) { $x++; } Returning References function &findIt($what) { global $myArray; return &$myArray[$what]; Useful applications are rather limited by Martin Kruliš (v2.0) 28. 2. 2019
References References vs. Pointers The unset() Function $x = 42; foo($x); How is $x affected? References vs. Pointers function foo(&$var) { $var = &$GLOBALS['bar']; } The unset() Function Does not remove data, only the variable Data are removed when not referenced The global Declaration global $a; $a = &$GLOBALS['a']; by Martin Kruliš (v2.0) 28. 2. 2019
Revising PHP Functions Declaration Keyword function followed by the identifier function foo([args, …]) { … body … } Function body Pretty much anything (even a function/class decl.) Nested functions/classes are declared once the function is called for the first time Functions are 2nd level citizens and identifier space is flat Results Optional argument of the return construct Only one value, but it can be an array or an object Note: The identifier namespace is indeed flat; however, we have explicit namespaces. I.e., the space is flat within each explicit (or default) namespace. by Martin Kruliš (v2.0) 28. 2. 2019
Function Arguments Argument Declarations Variable Number of Arguments Implicit values may be provided function foo($x, $y = 1, $z = 2) { … } Arguments with implicit values are aligned to the right Note that PHP functions does not support overloading Variable Number of Arguments func_num_args(), func_get_arg(), func_get_args() function foo($a, $b, ...$rest) $rest gets remaining arguments as an array Splat operator (…) works also for argument unpacking $args = [1, 2]; foo(...$args); // foo(1,2); by Martin Kruliš (v2.0) 28. 2. 2019
Static Variables Static Variables in Function Initialized on the first call Keep their values to subsequent calls function foo() { static $calls = 0; ++$calls; echo "foo() called $calls times..."; } foo(); // foo() called 1 times... foo(); // foo() called 2 times... Initial value must be a literal or an expression of literals (resolvable at compile time) Use static variables wisely. They are very powerful as they can help you in many scenarios (hiding private state, handling recursion, …). However, when you are using static variable, you should have probably used a class instead of a function. by Martin Kruliš (v2.0) 28. 2. 2019
Variable Functions Indirect Calling Similar Constructs Calling a function by its name stored in a variable function foo($x, $y) { … } $funcName = 'foo'; $funcName(42, 54); // the same as foo(42, 54); Similar Constructs Using specialized invocation functions call_user_func('foo', 42, 54); call_user_func_array('foo', array(42, 54)); by Martin Kruliš (v2.0) 28. 2. 2019
Anonymous Functions Anonymous Functions Better way how to implement nameless functions $fnc = function($args) { …body… }; The anonymous function is an instance of Closure It can be passed on like an object The visible variables must be explicitly stated $fnc = function(…) use ($var, &$refvar) { … }; These variables are captured in the closure Variables passed by reference can be modified PHP is not like JavaScript. Note that the anonymous functions do not work as methods: $obj = new StdClass(); $obj->fnc = function() { … }; Then $obj->fnc(); will not work, since fnc is not a method of StdClass. However, $fnc = $obj->fnc; $fnc(); will work as expected. by Martin Kruliš (v2.0) 28. 2. 2019
declare(strict_types=1); Type Hinting Controlling Types of Function Arguments Arguments may be prefixed with data type Regular type (string, array, …), class/interface name, callable, iterable, … Type prefixed with ? means null is also acceptable Return type may be also specified Automatic type coercing applied if possible TypeError exception thrown on error Strict mode disables coercing function foo(MyClass $obj, ?array $params): int Type without ? prefix also allows null, if null is default argument value. Read about strict mode (strict typing) in PHP 7: http://php.net/manual/en/functions.arguments.php Note that static languages tend to relax their type definitions (auto in C++, var in C#, …) and dynamic languages are introducing types (type hinging, linting, ...). Obviously, neither original paradigm was ideal and the best shall be found somewhere in the middle. declare(strict_types=1); by Martin Kruliš (v2.0) 28. 2. 2019
Class Declarations member visibility class Foo { public $var = 0; // a member variable public function bar() { // a method echo $this->var; } $instance = new Foo(); // create new instance $instance->var = 42; $instance->bar(); $instance = null; by Martin Kruliš (v2.0) 28. 2. 2019
Objects & References Objects Are Reference Types Like in Java or C# class Foo { public $bar = 0; public function __construct($b) { $this->bar = $b; } } $foo1 = new Foo(10); $foo2 = $foo1; $foo3 = &$foo1; $foo2 = new Foo(20); $foo3 = new Foo(30); $foo2 objref#2 objref#1 Foo(20) $foo1 objref#3 objref#1 Foo(10) $foo3 Foo(30) by Martin Kruliš (v2.0) 28. 2. 2019
Dynamic Nature of Classes Member Variables are Dynamic Why declare members in classes? Visibility control Default values (initialization) Better readability (documentation comments, …) Reflection class Point { public $x = 1; public $y = 2; } $p = new Point(); $p = new stdClass(); $p->x = 1; $p->y = 2; vs. Base class without any members (used also for implicit object constructions) For instance, when array is converted to an object, the class of that object is stdClass, whilst array keys become the member variables names. by Martin Kruliš (v2.0) 28. 2. 2019
Inheritance Standard Inheritance Model Overriding Methods Each class may have only one parent class Multi-inheritance is achieved by interfaces and traits Overriding Methods All methods act as if they are virtual parent::method() – calling overridden version AncestorClass::method() – calling explicit version Methods tagged as final cannot be overridden class MyFoo extends Foo { public function Bar() { parent::Bar(); } } by Martin Kruliš (v2.0) 28. 2. 2019
Static Members Static (Class) Members Declared by static keyword before the member Accessed by :: operator (like constants) E.g., MyClass::$statVar or MyClass::myFunc() One instance, no matter how many objects class has I.e., static methods does not have $this The same types of visibility as regular members Small differences in inheritance class A { public static $x; } class B extends A { public static $x; } class C extends A {} … C::$x = 42; new variable same as A::$x by Martin Kruliš (v2.0) 28. 2. 2019
Late Static Binding Late Binding for Static Calls When static:: is used instead of self:: class A { public static function who() { echo __CLASS__; } public static function test() { self::who(); } } class B extends A { public static function who() { echo __CLASS__; } } B::test(); static::who(); Note that this is quite a unique concept as many languages strictly distinguish between early (static) binding and late (dynamic) binding. In such languages, the term “late static binding” is an oxymoron. Prints ‘A’ Prints ‘B’ by Martin Kruliš (v2.0) 28. 2. 2019
Abstract Entities Abstract Classes and Methods Prefixed with keyword abstract Abstract class cannot be instantiated Abstract method has no body It is expected to be implemented in derived class abstract class AbstractClass { abstract function foo(); } class ConcreteClass extends AbstractClass { function foo() { … foo body … } $obj = new ConcreteClass(); by Martin Kruliš (v2.0) 28. 2. 2019
Interfaces Interfaces List of public methods a class must implement Interfaces may be extended like classes Using the extends operator interface IFoo { public function bar($goo); } class Foo implements IFoo { public function bar($goo) { ... Prior to PHP 5.3.9, a class could not implement two interfaces that specified a method with the same name, since it would cause ambiguity. More recent versions of PHP allow this as long as the duplicate methods have the same signature. Unlike in case of inheritance, a class may implement multiple interfaces by Martin Kruliš (v2.0) 28. 2. 2019
Traits Traits Class-like mechanism for code reuse Trait Horizontal composition of behavior (similar to Mixins) Trait Special class that cannot be instantiated May contain both member variables and methods It can be added to regular classes trait OmniSaluter { public function helloWorld() { echo 'Hello World'; } } class myClass { use OmniSaluter; ... Traits have quite complex behavior, especially when combined with other OOP techniques such as inheritance or interfaces. See PHP documentation for details. by Martin Kruliš (v2.0) 28. 2. 2019
Object Iterators Iterating Member Variables By foreach construct (like arrays) Keys are strings with the name of the member Only visible (accessible) members are iterated class MyClass { public $var1 = 1; public $var2 = 2; private $var3 = 3; } $obj = new MyClass(); foreach ($obj as $key => $value) { ... } Custom iteration can be implemented Interface Iterator and IteratorAggregate Both Iterator and IteratorAggregate interfaces extend abstract Traversable interface, which is empty, but it can be used to test an object, whether it has a custom iterator (by the means of instanceof operator). by Martin Kruliš (v2.0) 28. 2. 2019
Object Iterators Example class ArrayWrapper implements Iterator { private $items = [ 1, 2, 3 ]; public function rewind() { // initialize for new iteration reset($this->items); } public function current() { // value at actual position return current($this->items); } public function key() { // key at actual position return key($this->items); } public function next() { // advance position by one step return next($this->items); } public function valid() { // is current position valid return ($this->current() !== false); } } by Martin Kruliš (v2.0) 28. 2. 2019
Local context is preserved Generators Detached Custom Iterators The foreach construct is powerful But it iterates over structures (arrays and objects) Custom iterator can be built (Iterator interface) Both memory demanding and tedious Generator is a function that yields values It can be used in foreach construct function range_gen($from, $to, $step) { for ($i = $from; $i < $to; $i += $step) yield $i; } foreach (range_gen(1,10,2) as $value) ... Returns next value Local context is preserved by Martin Kruliš (v2.0) 28. 2. 2019
Object Cloning Copying Reference vs. Copying Object Assignment copies reference, not the object Object copy must be invoked explicitly, by cloning $foo = new Foo(); $foo2 = $foo; $foo3 = clone $foo; Foo object #1 Note that human cloning is prohibited by law in many countries (https://en.wikipedia.org/wiki/Human_cloning). $foo $foo2 Foo object #2 $foo3 by Martin Kruliš (v2.0) 28. 2. 2019
$this is newly copied object, which has all members already assigned Object Cloning Shallow vs. Full Copy Cloning process creates shallow copy by default Assignment operator is used on every member Post-cloning operations may be implemented in method __clone(), which is invoked on the copy public function __clone() { $this->innerObj = clone $this->innerObj; } $this is newly copied object, which has all members already assigned by Martin Kruliš (v2.0) 28. 2. 2019
Object Cloning Example class InnerFoo { public $bar = 1; } class Foo { public $innerFoo; public function __construct() { $this->innerFoo = new InnerFoo(); } public function __clone() { $this->innerFoo = clone $this->innerFoo; $foo = new Foo(); $foo2 = clone $foo; Ensures deep copy by Martin Kruliš (v2.0) 28. 2. 2019
Magic Methods Member Variables Accessors __get() – control read-access to members __set() – control write-access to members __isset() – isset() override for members __unset() – unset() override for members Overrides access to member variables, which are not declared or not visible Declared variables are accessed directly Only for regular members, not for static Handle with care They may lead to less readable code or even errors Implementing magic methods is sometimes called “overloading” in PHP. Do not mix-up with regular overloading that exists in other languages. There is some discussion whether using this magic assessors is actually good or bad. On one side, they may shorten your code (let you express more complex things with less writing). On the other hand, they could be slower in execution and they may create more obfuscated code (documenting magic members is tedious, there could be no autocompletion in your IDE, etc.). The following two examples show good (justifiable) applications of accessors: You have an object that carries name-value pairs and you want the user to read the values easily, but not to be able to modify them (or only via methods). Mark all values private and write a __get method, which provides the access to them even from outside of the object. Absence of __set method will result in error when anyone wants to write the properties from the outside. You have a generic class/object, that represents e.g., a node in a complex tree structure (like XML). The accessors can be used to read or modify the structure itself (see the embedded SimleXMLElement class). Otherwise it might be better to use regular methods to achieve what you are doing/could do with magic methods. by Martin Kruliš (v2.0) 28. 2. 2019
Magic Methods Method Invocation Override Array Access Interface __call() – intercepts calls to not visible methods __callStatic() – the same for static methods __invoke() – when object is called as function Array Access Interface Allows using the object as an array ($obj[…]) boolean offsetExists(mixed $offset) mixed offsetGet(mixed $offset) void offsetSet(mixed $offset, mixed $value) void offsetUnset(mixed $offset) by Martin Kruliš (v2.0) 28. 2. 2019
Magic Methods Example class Readonly { private $foo; ... public function __construct($foo) { $this->foo = $foo; } public function __get($name) { return (isset($this->$name)) ? $this->$name; : null; } public function __isset($name) { return isset($this->$name); public function __set($name, $value) { throw new Exception("Object is read only!"); public function __unset($name) { } by Martin Kruliš (v2.0) 28. 2. 2019
Serialization Object (De)Serialization Using magic methods __sleep() – invoked when the object is being serialized (to a persistent storage) __wakeup() – invoked when the object is being deserialized (from a persistent storage) __toString() – returns string representation of the object (e.g., so it can be printed, logged, …) Using Serializable interface string serialize(void) void unserialize (string $serialized) Serializable interface is newer and preferred as it provides better control over the serialization process. Note that object serialization an deserialization may be done manually (see serialize() and unserialize() global functions). by Martin Kruliš (v2.0) 28. 2. 2019
Comparing Objects Reference Comparison Behavior $object1 == $object2 True if both object are of the same class and all member variables are equal (==) $object1 === $object2 True if both variables hold a reference to exactly the same object $object1 < $object2 Works only on objects of the same class Returns the result of comparison of the first non-equal property Use with extra care (note that sort() uses comparisons) by Martin Kruliš (v2.0) 28. 2. 2019
Type Detection/Verification Operator instanceof Verifies whether object is an instance of given class or derived class, or implements given interface if ($foo instanceof FooClass) ... Functions Testing Types get_class() – returns class name as string get_parent_class() – name of the parent class is_a() – verifies that object is of given class is_subclass_of() – like is_a(), but checks also derived classes by Martin Kruliš (v2.0) 28. 2. 2019
Reflection Reflection A mechanism implemented in (dynamic) languages to inspect types, objects, classes, etc. at runtime PHP holds a specific reflector class for each entity ReflectionType ReflectionFunction ReflectionClass ReflectionObject ReflectionProperty ReflectionParameter … by Martin Kruliš (v2.0) 28. 2. 2019
Reflection Reflection API in PHP An object of appropriate reflector is instantiated E.g., to list information about a class, an object of ReflectionClass is created (by the name of the class) Each reflector provides methods to access the data Class/Object reflector allows listing properties, methods, constants, and inspect inheritance Function/Method reflectors give information about arguments, modifiers, and creates dynamic closure … API also provides access to doc comments /** … */ Can be used for custom annotations Example by Martin Kruliš (v2.0) 28. 2. 2019
Namespaces Namespaces Another way how to encapsulate space of identifiers Affect classes, traits, interfaces, functions, constants Similar to directories and files Declaration: namespace identifier; First statement in the file Identifier may be hierarchical (separator is backslash) Dereferencing myClass -> currentNS\myClass name\space\myClass -> currentNS\name\space\myClass \name\space\myClass – absolute path, no modifications Aliasing – use identifier [as identifier]; Note that namespaces do not affect global variables. by Martin Kruliš (v2.0) 28. 2. 2019
Anonymous Classes Instant One-use Classes Similar to anonymous functions interface Logger { public function log(string $msg); } ... $app->addLogger(new class implements Logger { public function log(string $msg) { echo $msg; }); by Martin Kruliš (v2.0) 28. 2. 2019
Discussion by Martin Kruliš (v2.0) 28. 2. 2019