Readonly properties
class PostData
{
public function __construct(
public readonly string $title,
public readonly string $author,
public readonly string $body,
public readonly DateTimeImmutable $createdAt,
public readonly PostState $state,
) {}
}Constructor property promotion
PHP ≥ 8
class Class
{
private int $x;
public ?float $y;
function __construct(
int $x = 23,
?float $y = null
) {
$this->x = $x;
$this->y = $y;
}
}Can be simplified to:
class Class
{
function __construct(
private int $x = 23,
public ?float $y = null
) { }
}__toString
class Car
{
public function __construct(
private string name,
private int maxSpeed
) {}
public function __toString()
{
return "The car ".$this->name." drives at max ".$this->maxSpeed." km/h";
}
}
$car = new Car("Peugeot", 210);
echo $car; // The car Peugeot drives at max 210 km/hClass function chaining
class Transaction
{
private int $amount;
function __construct()
{
$this->amount = 100;
}
function add(int $value)
{
$this->amount += $value;
return this;
}
function remove(int $value)
{
$this->amount -= $value;
return this;
}
}$transaction = new Transaction();
$transaction->add(40)->remove(90);Static keyword
function count()
{
static $i = 0;
return $i++;
}
echo count(); // 1
echo count(); // 2
echo count(); // 3Class constants
Recommended: Always define access modifiers
class Transaction
{
public const STATUS_PAID = "paid";
public function __construct()
{
echo self::STATUS_PAID;
}
}
echo Transaction::STATUS_PAID;
$transaction = new Transaction();Magic Class Constant ::class
Resolves the fully qualified class name
namespace foo
{
class bar
{
// ...
}
echo bar::class; // foo\bar
}Static properties
class Transaction
{
static int $count = 0;
public function __construct()
{
$self::count++;
}
}
$transaction = new Transaction();
$transaction = new Transaction();
$transaction = new Transaction();
echo Transaction::$count; // 3Clone Classes
$obj1 = new Class();
$obj2 = clone $obj1;Patterns
Enums
Enumerations are a restricting layer on top of classes and class constants, intended to provide a way to define a closed set of possible values for a type.
enum InvoiceStatus: int
{
case Pending = 0;
case Paid = 1;
case Failed = 2;
}Interfaces
Interfaces are like abstract classes They can be implemented like classes can be extended Interfaces can extend other interfaces Classes can implement more than one interface, separated by comma
interface Collector
{
public function collect($amount);
}
class CollectingAgency implements Collector
{
public function collect($amount)
{
// ...
}
}Traits
Like classes, can be extended and provide functionality.
However, are not valid classes itself
trait Hello {
public function sayHello() {
echo 'Hallo ';
}
}
trait World {
public function sayWorld() {
echo ' Welt';
}
}
class MyHelloWorld {
use Hello, World;
public function sayExclamationMark() {
echo '!';
}
}Namespaces
Namespace aliasing
use Namespace\To\The\Thing as NewThing;
new NewThing(); // worksImporting multiple things from one namespace
use Namespace\To\More\Things\{Thing1, Thing2};
// Or just import the whole namespace
use Namespace\To\More\Things;