
This is a part of my nostalgic journey to the roots of my programming adventure: the Php.
More specifically, this is a collection of re-freshed notes and some kind of cheat-sheet for the Php language which I decided lately to revisit. About which you can read more in my previous post.
Since no one is really reading my blog and the site is more like a personal archive, I can always come back to it when needed - which makes it a best place to store notes in this way.
PHP is like a Swiss Army knife. Itβs not the best tool for any one job, but itβs incredibly versatile.
In order to get Php running in your local environment, you should at least have Php installed, which can be done in multiple ways, depending on your OS.
Since I work in hybrid environment, I usually use mix of local installation and Docker containers and WSL2 - it would take a while to describe all the options, so I will just point you to the official Php installation guide or the easier way: the Laravel Herd or Laragon if your are on Windows or official CLI installers for your Linux distro.
Once you have Php installed, you can check if everything is working by running:
php -v
Now create a directory to store your Php files, e.g. php-notes, and inside create a file named index.php with the following content:
<?php
echo "Hello, World! \n";
Which is the same as console.log in JavaScript or print in Python.
And we are ready to go. You can run your script using the built-in Php server by executing:
php index.php
Or with a local server:
php -S localhost:8000
Then open your browser and navigate to http://localhost:8000 to see the output.
As you probably already know, to declare a variable we use the famous dollar sign $ followed by the variable name:
$name = "John Doe"; // String
$age = 30; // Integer
$height = 5.9; // Float
$isStudent = false; // Boolean
$nullValue = null; // Null
To delete a variable, you can use the unset() function:
unset($name);
Contants can be defined using the define() function or the const keyword:
define("PI", 3.14);
echo "Value of PI is " . PI . "\n";
const E = 2.71;
echo "Value of E is " . E . "\n";
Spaceship operator (<=>) is used for three-way comparison
$result = 5 <=> 10; // -1
$result2 = 10 <=> 5; // 1
$result3 = 5 <=> 5; // 0
echo "Spaceship operator results: $result, $result2, $result3\n";
All other operators are pretty much standard and similar to other languages.
You can also un-pack arrays into variables using the list() function or the shorthand [] syntax:
$address = ['123 Main St', 'Pine Ridge', 'CA', '90210'];
[$street, $city, $state, $zip] = $address;
[,, $stateOnly, ] = $address; // Skipping values
echo "The state: $stateOnly \n"; // The state: CA
In Php, you can cast variables to different types using the (type) syntax:
$number = "42";
$casted = (int)$number; // Cast to integer
echo "Casted value: $casted\n";
The Php has two main collection types: arrays and objects (associative arrays):
$fruits = ["Apple", "Banana", "Cherry"]; // Array
$fruits[] = "Mango"; // Adding an element to the array
array_push($fruits, "Orange"); // Another way to add an element
unset($fruits[1]); // Removing an element (Banana)
// Looping through an array
foreach ($fruits as $fruit) {
echo "Fruit: $fruit\n";
}
$person = ["name" => "John", "age" => 30]; // Associative Array, most commonly used
echo "The name is: $person[name] and age is: $person[age] \n";
$person["height"] = 5.9; // Adding a new key-value pair
echo "The height is: $person[height] \n";
// Looping through an associative array
foreach ($person as $key => $value) {
echo "$key: $value\n";
}
The arrays can be "mixed", meaning they can hold different data types:
$mixed = [
"name" => "Alice",
18,
"other value",
"isStudent" => true,
];
$mixed["email"] = "alice@queen.co";
foreach ($mixed as $key => $value) {
echo "$key: $value\n";
}
Those can be also more complex, nested arrays:
$config = [
"database" => [
"host" => "localhost",
"user" => getenv("DB_USER"),
"password" => getenv("DB_PASSWORD"),
],
"app" => [
"debug" => true,
"version" => "1.0.0",
],
];
echo "Database host: " . $config["database"]["host"] . "\n";
Control structures in Php are similar to other C-like languages:
function keyword, or by using arrow functions (PHP 7.4+).for, foreach, while, and do...while loops are available.if, else, elseif, and switch statements are used for branching logic.Few examples:
// The data
$nums = [1, 2, 3, 4, 5];
// Arrow functions with map
$squared = array_map(fn($n) => $n * $n, $nums);
echo "Squared numbers: " . implode(", ", $squared) . "\n";
// Arrow functions with filter
$even = array_filter($nums, fn($n) => $n % 2 === 0);
echo "Even numbers: " . implode(", ", $even) . "\n";
// Classic arrow function
$double = fn($x) => $x * 2;
echo "Doubled value of 4 is: " . $double(4) . "\n";
// Optionals
function add(int $a, int $b, ?int $c = null): int
{
return $a + $b + ($c ?? 0);
}
echo "Sum: " . add(5, 10) . "\n"; // 15
echo "Sum with optional: " . add(5, 10, 5) . "\n"; // 20
// Default parameters
function greet(string $name = "Guest"): string
{
return "Hello, $name!";
}
There are also enums (Php 8.1+) for better type safety:
enum UserRole: string {
case ADMIN = 'admin';
case EDITOR = 'editor';
case VIEWER = 'viewer';
}
function getPermissions(UserRole $role): array {
return match ($role) {
UserRole::ADMIN => ['create', 'edit', 'delete', 'view'],
UserRole::EDITOR => ['edit', 'view'],
UserRole::VIEWER => ['view'],
};
}
$role = UserRole::EDITOR;
$permissions = getPermissions($role);
echo "Permissions for " . $role->value . ": " . implode(", ", $permissions) . "\n"; // Permissions for editor: edit, view
And there are also named arguments and more advanced function signatures:
// Usage of named arguments (parameters) (Php 8.0+)
enum Runner {
case SWARM;
case SINGLE;
case KUBERNETES;
}
function setConfiguration(Runner $runner, int $maxJobs = 10, bool $debug = false): void {
$config = [
"runner" => $runner->name,
"max_jobs" => $maxJobs,
"debug" => $debug,
];
echo "Configuration set: " . json_encode($config) . "\n";
}
setConfiguration(runner: Runner::KUBERNETES, maxJobs: 15, debug: true);
setConfiguration(runner: Runner::SINGLE, debug: true);
// Classic while loop
while ($age < 18) {
echo "Age is $age, still a minor.\n";
$age++;
}
// Do while loop
$age = 13;
do {
echo "Age is $age, still a minor.\n";
$age++;
} while ($age < 18);
// Classic for loop
for ($i = 0; $i <= count($fruits); $i++) {
echo "Fruit at index $i is: " . $fruits[$i] . "\n";
}
// Alternative syntax for control structures (useful in templates)
?>
<?php if ($x): ?>
This is displayed if the test is truthy.
<?php else: ?>
This is displayed otherwise.
<?php endif; ?>
But there are some interesting things like match expression (Php 8.0+) in more functional style, together with arrow functions (Php 7.4+) or more newer pipe operator (Php 8.5+) or array_first() or array_last().
$age = 15;
$cat = match (true) {
$age < 13 => "Child",
$age >= 13 && $age < 20 => "Teenager",
$age >= 20 && $age < 65 => "Adult",
default => "Senior",
};
echo "Category: $cat \n"; // Category: Teenager
$output = " Docker Runner "
|> trim(...)
|> strtolower(...)
|> (fn($str) => str_replace(" ", "_", $str));
echo "Transformed output: $output \n"; // Transformed output: docker_runner
Of course there are also if statements or ternary operators:
$age = 18;
// If statement
if ($age < 18) {
echo "Minor";
} elseif ($age < 65) {
echo "Adult";
} else {
echo "Senior";
}
// Ternary operator
$status = ($age < 18) ? "Minor" : "Adult";
echo "Status: $status\n";
In Php since version 7.0 you can enforce types for function parameters and return values. You can specify types like int, float, string, bool, array, object, callable, and even class/interface names.
declare(strict_types=1);
Php supports object-oriented programming (OOP).
We would start with the most basic example of a class with properties and methods:
class Store {
public string $storeInternalCode;
public array $config;
public function isOpen(): bool {
$hour = (int)date('H');
return $hour >= 9 && $hour <= 21;
}
}
$store = new Store();
$store->storeInternalCode = "STORE_001";
$store->config = [
"currency" => "USD",
"size" => "Large",
"address" => [
"street" => "123 Main St",
"city" => "Pine Ridge",
"zip" => "12345",
]
];
echo "Store Code: " . $store->storeInternalCode . "\n"; // Store Code: STORE_001
echo "Is store open? " . ($store->isOpen() ? "Yes" : "No") . "\n"; // Is store open? Yes/No
// Depending on current time
echo "Store City: " . $store->config["address"]["city"] . "\n"; // Store City: Pine Ridge
But you can always use constructors to initialize properties:
class Store {
public function __construct(public string $storeInternalCode, public array $config) {
$this->storeInternalCode = $storeInternalCode;
$this->config = $config;
}
public function isOpen(): bool {
$hour = (int)date('H');
return $hour >= 9 && $hour <= 21;
}
}
$store = new Store(
storeInternalCode: "STORE_001",
config: [
"currency" => "USD",
"size" => "Large",
"address" => [
"street" => "123 Main St",
"city" => "Pine Ridge",
"zip" => "12345",
]
]
);
echo "Is store open? " . ($store->isOpen() ? "Yes" : "No") . "\n";
Of course, you can always use visibility modifiers (public, protected, private), destructors, static properties/methods, abstract classes, interfaces, and traits to build more complex OOP structures.
For example, here is another example with static properties and methods, constructors, and more complex logic:
class Invoice {
public static array $invoiceNumbers = [];
public Store $store;
public string $invoiceNumber;
public function __construct(Store $store) {
$this->store = $store;
}
private function generateInvoiceNumber(): string {
do {
$number = 'INV-' . strtoupper(bin2hex(random_bytes(4)));
} while (in_array($number, self::$invoiceNumbers));
self::$invoiceNumbers[] = $number;
return $number;
}
public function createInvoice(): void {
$this->invoiceNumber = $this->generateInvoiceNumber();
echo "Invoice " . $this->invoiceNumber . " created for store " . $this->store->storeInternalCode . "\n";
}
}
$invoice = new Invoice($store);
$invoice->createInvoice();
echo "Invoice Number: " . $invoice->invoiceNumber . "\n"; // Invoice Number: INV-XXXXXXX
There is a slight difference in defining classes in pre and post Php 8.0 versions, thanks to the new constructor property promotion feature:
Pre Php 8.0:
class User {
public string $name;
public int $age;
public function __construct(string $name, int $age) {
$this->name = $name;
$this->age = $age;
}
}
Post Php 8.0
class User {
public function __construct(public string $name, public int $age) {}
public function isAdult(): bool {
return $this->age >= 18;
}
}
There is no need to explicitly declare properties and assign them in the constructor - the promotion does it automatically.
So no more typing $this->property = $property; for each property.
Php of course supports inheritance (the classical Animal and Cat example):
class Animal {
public function makeSound(): string {
return "Some generic sound";
}
}
class Cat extends Animal {
public function makeSound(): string {
return "Meow";
}
}
$cat = new Cat();
echo $cat->makeSound(); // Meow
You can also block inheritance using the final keyword:
class Chasis {
public final function getMaterial(): string {
return "Aluminum";
}
}
class Car extends Chasis {
// This will cause an error
// public function getMaterial(): string {
// return "Steel";
// }
And also use Union Types:
class Discount {
public function applyDiscount(int|float $amount, int|float $discount): int|float {
return $amount - $discount;
}
}
Similarly to other OOP languages, Php supports interfaces to define contracts for classes:
interface Logger {
public function log(string $message): void;
}
class FileLogger implements Logger {
public function log(string $message): void {
file_put_contents('app.log', $message . PHP_EOL, FILE_APPEND);
}
}
$logger = new FileLogger();
$logger->log("This is a log message.");
trait LoggerTrait {
public function log(string $message): void {
file_put_contents('app.log', $message . PHP_EOL, FILE_APPEND);
}
}
class FileLogger {
use LoggerTrait;
}
$logger = new FileLogger();
$logger->log("This is a log message.");
The main difference between traits and interfaces is that traits can provide default implementations for methods, while interfaces cannot, and they can be used to compose behavior across multiple classes.
So in other words, traits are neither classes nor interfaces - they are reusable pieces of code that can be included within classes to share functionality.
In order to use traits, you use the use keyword inside a class definition, like shown in the example above.
Php uses namespaces to organize code and avoid name collisions. You can define a namespace at the top of your Php file using the namespace keyword:
# model/ExampleModel.php
namespace App\Models;
class ExampleModel {
public function getData(): string {
return "Some data from ExampleModel";
}
}
And then you can import and use that class in another file using the use keyword:
use App\Models\ExampleModel;
$model = new ExampleModel();
echo $model->getData(); // Some data from ExampleModel
So far so good!
The overall feel of modern Php is quite nice and familiar if you have experience with other C-like languages.
It feels kinda very similar to I am use do in Typescript and feels really productive and nice to write and read, especially using modern features like arrow functions, match expressions, union types, constructor property promotion, interfaces, traits, and more.
Time to deep-dive into the Laravel world next!
PS. Here is also a small cheat-sheet of some common standard library functions for quick reference, below.
Here are some common standard library functions for OS, files, env, and related tasks, grouped by purpose.
$s = file_get_contents('data.txt'); file_put_contents('out.txt', $s);allow_url_fopen is enabled).php.ini settings at runtime.proc_* for fine-grained control.