edgaralexanderfr / php-types
Library intended to expand PHP's data types and useful data structures as well as strong types consistency in the code of target projects.
README
PHP Types is a small library/framework aimed to improve and encourage strong typing across your project's codebase, consisting of basic array-types, useful data structures and more, that are not natively available by the language itself.
Table of contents 📖
- 3.1 Primitive types
- 3.2 Primitive arrays
- 3.3 Standard types
- 3.4 Data structures
- 3.5 Type errors
- 3.6
hasAny()
andisEmpty()
methods - 3.7 The
splice
method - 3.8 The
length
property - 3.9 Defining custom types
Requirements
- PHP 8.3.0 or major
- Composer (optional)
- Have an initted Composer project (optional)
Installation
Install PHP Types via Composer:
composer require edgaralexanderfr/php-types
or:
You can always download the library as .zip file, decompress it, store it somewhere in your target project and include the autoload.php file from the library's project root:
curl -L -o php-types-master.zip https://github.com/edgaralexanderfr/php-types/archive/refs/heads/master.zip \ && unzip php-types-master.zip \ && rm php-types-master.zip
or:
You can download the packed .phar version of the library:
mkdir lib \
&& curl -L -o lib/php-types.phar https://github.com/edgaralexanderfr/php-types/raw/master/lib/php-types.phar
<?php declare(strict_types=1); include 'lib/php-types.phar'; use function PHPTypes\Primitive\string_array; $message = string_array('Hello', 'world', '!'); print_r($message);
Usage
Primitive types
Extending PHP primitive types
PHP Types adds some cool extra types that you can play around with:
<?php declare(strict_types=1); include 'vendor/autoload.php'; use function PHPTypes\Primitive\byte; use function PHPTypes\Primitive\char; use function PHPTypes\Primitive\uchar; /** @var byte (Extends from `uint8_t`). */ $byte = byte(255); /** @var char */ $char = char('c'); /** @var uchar */ $uchar = uchar('A'); /** @var char */ $string = char('Hello!'); // Since `char` can only store a single char, `$string` will be '!' and a PHP Warning will be notified. echo $byte . PHP_EOL; echo $char . PHP_EOL; echo $uchar . PHP_EOL; echo $string . PHP_EOL;
php examples/primitives.php PHP Warning: Character constant too long for its type Warning: Character constant too long for its type 255 c A !
ObjectType
<?php declare(strict_types=1); include 'vendor/autoload.php'; use PHPTypes\Primitive\object_t; use function PHPTypes\Primitive\object_t; function display(object_t $object): void { echo "{$object->name}:" . PHP_EOL; echo $object->json() . PHP_EOL; } $object = object_t([ "name" => "Ford Mustang GT", "brand" => "Ford", "category" => "Muscle Car", "gas" => 0.8, "engine" => object_t([ "type" => "V8", "rpm" => 750, ]), "transmission" => object_t([ "type" => "manual", "gear" => 1, "gears" => ["R", "N", "1", "2", "3", "4", "5", "6"], ]), ]); display($object);
php examples/object.php Ford Mustang GT: {"name":"Ford Mustang GT","brand":"Ford","category":"Muscle Car","gas":0.8,"engine":{"type":"V8","rpm":750},"transmission":{"type":"manual","gear":1,"gears":["R","N","1","2","3","4","5","6"]}}
Primitive arrays
BoolArray
<?php declare(strict_types=1); include 'vendor/autoload.php'; use PHPTypes\Primitive\bool_array; use function PHPTypes\Primitive\bool_array; function display(bool_array $array): void { foreach ($array as $value) { echo $value . PHP_EOL; } } $array = bool_array(false, true, false); display($array);
php examples/bool_array.php 1
IntArray
<?php declare(strict_types=1); include 'vendor/autoload.php'; use PHPTypes\Primitive\int_array; use function PHPTypes\Primitive\int_array; function display(int_array $array): void { foreach ($array as $value) { echo $value . PHP_EOL; } } $array = int_array(1, 2, 3); display($array);
php examples/int_array.php 1 2 3
FloatArray
<?php declare(strict_types=1); include 'vendor/autoload.php'; use PHPTypes\Primitive\float_array; use function PHPTypes\Primitive\float_array; function display(float_array $array): void { foreach ($array as $value) { echo $value . PHP_EOL; } } $array = float_array(0.1, 2.3, 4.5); display($array);
php examples/float_array.php 0.1 2.3 4.5
StringArray
<?php declare(strict_types=1); include 'vendor/autoload.php'; use PHPTypes\Primitive\string_array; use function PHPTypes\Primitive\string_array; function display(string_array $array): void { foreach ($array as $value) { echo $value . PHP_EOL; } } $array = string_array('🍎', '🍊', '🍌'); display($array);
php examples/string_array.php 🍎 🍊 🍌
ObjectArray
<?php declare(strict_types=1); include 'vendor/autoload.php'; use PHPTypes\Primitive\object_array_t; use function PHPTypes\Primitive\object_t; use function PHPTypes\Primitive\object_array_t; function display(object_array_t $array): void { foreach ($array as $value) { print_r($value); } } $array = object_array_t( object_t([ 'id' => 1, 'name' => 'Charles Babbage', ]), object_t([ 'id' => 2, 'name' => 'Alan Turing', ]), object_t([ 'id' => 3, 'name' => 'Edsger Dijkstra', ]), ); display($array);
php examples/object_array.php PHPTypes\Primitive\object_t Object ( [id] => 1 [name] => Charles Babbage ) PHPTypes\Primitive\object_t Object ( [id] => 2 [name] => Alan Turing ) PHPTypes\Primitive\object_t Object ( [id] => 3 [name] => Edsger Dijkstra )
Extra primitives arrays
<?php declare(strict_types=1); include 'vendor/autoload.php'; use function PHPTypes\Primitive\byte_array; use function PHPTypes\Primitive\char_array; use function PHPTypes\Primitive\uchar_array; $byte_array = byte_array(0, 255, 0, 255); $char_array = char_array('H', 'e', 'l', 'l', 'o', '!'); $uchar_array = uchar_array('a', 'b', 'c'); var_dump($byte_array); // Notice how we can print out `char_array`s just like usual strings: echo $char_array . PHP_EOL; echo $uchar_array . PHP_EOL;
php examples/primitives_arrays.php object(PHPTypes\Primitive\byte_array)#2 (2) { ["object":protected]=> array(1) { ["PHPTypes\Primitive\byte"]=> string(23) "PHPTypes\Primitive\byte" } ["storage":"ArrayIterator":private]=> array(4) { [0]=> object(PHPTypes\Primitive\byte)#6 (1) { ["val":protected]=> int(0) } [1]=> object(PHPTypes\Primitive\byte)#7 (1) { ["val":protected]=> int(255) } [2]=> object(PHPTypes\Primitive\byte)#8 (1) { ["val":protected]=> int(0) } [3]=> object(PHPTypes\Primitive\byte)#9 (1) { ["val":protected]=> int(255) } } } Hello! abc
Standard types
Standard Ints
Similarly to C, you can make use of the standard types (as you would by including the <stdint.h> standard library) to specify and maintain integer values in certain ranges:
<?php declare(strict_types=1); include 'vendor/autoload.php'; use function PHPTypes\Std\int16_t; use function PHPTypes\Std\int8_t; use function PHPTypes\Std\uint16_t; use function PHPTypes\Std\uint8_t; /** @var int8_t [-128...127] */ $int8_t = int8_t(0); /** @var uint8_t [0...255] */ $uint8_t = uint8_t(0); /** @var int16_t [-32768...32767] */ $int16_t = int16_t(0); /** @var uint16_t [0...65535] */ $uint16_t = uint16_t(0); // Assigning/accessing values: $int8_t->value = 256; $uint8_t->value = -128; $int16_t->value = 1024; $uint16_t->value = 2048; // Displaying new values // (Notice how the first 2 variables overflow): echo $int8_t . PHP_EOL; echo $uint8_t . PHP_EOL; echo $int16_t . PHP_EOL; echo $uint16_t . PHP_EOL;
php examples/stdint.php 0 128 1024 2048
Note: keep in mind that these are only representative values and not actual low-level values where we're not saving space by storing specific bytes per integer.
size_t
We can also make use of the size_t
data type to store large numbers based on sizes, lengths, etc:
<?php declare(strict_types=1); include 'vendor/autoload.php'; use function PHPTypes\Std\size_t; /** @var size_t [0...PHP_INT_MAX] */ $size_t = size_t(0); $size_t->value--; echo $size_t->value . PHP_EOL;
php examples/size_t.php 9223372036854775806
Standard Ints Arrays
<?php declare(strict_types=1); include 'vendor/autoload.php'; use PHPTypes\Std\Int16Array; use PHPTypes\Std\Int8Array; use PHPTypes\Std\UInt16Array; use PHPTypes\Std\UInt8Array; use function PHPTypes\Std\int16_array; use function PHPTypes\Std\int8_array; use function PHPTypes\Std\size_array; use function PHPTypes\Std\uint16_array; use function PHPTypes\Std\uint8_array; /** @var int8_array */ $int8_array = int8_array(-3, -2, -1); /** @var uint8_array */ $uint8_array = uint8_array(0, 1, 2); /** @var int16_array */ $int16_array = int16_array(3, 4, 5); /** @var uint16_array */ $uint16_array = uint16_array(6, 7, 8); /** @var size_array */ $size_array = size_array(9, 10, 11); // or: /** @var Int8Array */ $int8_array = new Int8Array(-3, -2, -1); /** @var UInt8Array */ $uint8_array = new UInt8Array(0, 1, 2); /** @var Int16Array */ $int16_array = new Int16Array(3, 4, 5); /** @var UInt16Array */ $uint16_array = new UInt16Array(6, 7, 8);
Data structures
HashSet
<?php declare(strict_types=1); include 'vendor/autoload.php'; use PHPTypes\Set\HashSet; $set = new HashSet(); $set->add(1); $set->add('two'); $set->add(3); $set->add(3); $set->add('two'); $set->add('one'); foreach ($set as $value) { echo $value . PHP_EOL; }
php examples/hash_set.php 1 two 3 one
IntHashSet
<?php declare(strict_types=1); include 'vendor/autoload.php'; use PHPTypes\Set\IntHashSet; $set = new IntHashSet(); $set->add(1); $set->add(2); $set->add(3); $set->add(3); $set->add(2); $set->add(1); $set->add(0); foreach ($set as $value) { echo $value . PHP_EOL; }
php examples/int_hash_set.php 1 2 3 0
StringHashSet
<?php declare(strict_types=1); include 'vendor/autoload.php'; use PHPTypes\Set\StringHashSet; $set = new StringHashSet(); $set->add('🍎'); $set->add('🍊'); $set->add('🍌'); $set->add('🍌'); $set->add('🥭'); foreach ($set as $value) { echo $value . PHP_EOL; }
php examples/string_hash_set.php 🍎 🍊 🍌 🥭
Type errors
In case you attempt to assign a value with a type different than an array's type, a TypeError
is thrown:
<?php declare(strict_types=1); include 'vendor/autoload.php'; use function PHPTypes\Primitive\int_array; $array = int_array(1, 2, 3); try { $array[2] = '🥭'; } catch (TypeError $e) { echo $e->getMessage() . PHP_EOL; } try { $array[] = '🥭'; } catch (TypeError $e) { echo $e->getMessage() . PHP_EOL; } $array[] = 4; print_r($array);
php examples/type_error.php Element must be of type integer, string given, called Element must be of type integer, string given, called PHPTypes\Primitive\int_array Object ( [type:protected] => integer [storage:ArrayIterator:private] => Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 4 ) )
hasAny()
and isEmpty()
methods
Arrays contain useful methods that help to determine whether if they're empty or contain at least 1 element in them:
<?php declare(strict_types=1); include 'vendor/autoload.php'; use function PHPTypes\Primitive\object_array; use function PHPTypes\Primitive\string_array; $fruits = string_array('🥭'); if ($fruits->hasAny()) { echo '`$fruits` contains at least 1 element.' . PHP_EOL; } $objects = object_array(); if ($objects->isEmpty()) { echo '`$objects` is an empty array.' . PHP_EOL; }
php examples/has_any_is_empty.php `$fruits` contains at least 1 element. `$objects` is an empty array.
The splice
method
You can make use of the splice
method from array
s the same way you'd use the array_splice
function
with normal array
s:
<?php declare(strict_types=1); include 'vendor/autoload.php'; use function PHPTypes\Primitive\string_array; $fruits = string_array('🍎', '🍊', '🥭', '🍌'); [$without_mango, $mango] = $fruits->splice(2, 1); print_r($without_mango); print_r($mango);
php examples/splice.php PHPTypes\Primitive\string_array Object ( [type:protected] => string [storage:ArrayIterator:private] => Array ( [0] => 🍎 [1] => 🍊 [2] => 🍌 ) ) PHPTypes\Primitive\string_array Object ( [type:protected] => string [storage:ArrayIterator:private] => Array ( [0] => 🥭 ) )
The splice
method returns a multiple
, consisting of the resultant array along with the extracted elements respectively.
The length
property
Similarly to JavaScript/JS, you can make use of the length
property to retrieve the count
of total elements from a specific array
:
<?php declare(strict_types=1); include 'vendor/autoload.php'; use PHPTypes\Std\UInt8Array; $bytes = new UInt8Array(0, 1, 2, 4, 8, 16, 32, 64, 128); echo $bytes->length . PHP_EOL;
php examples/length.php 9
Defining custom types
Defining custom arrays
To define custom arrays, you can create a new class
that extends PHPTypes\ArrayObject
and implements a typed constructor for such purpose, e.g:
<?php declare(strict_types=1); include 'vendor/autoload.php'; use PHPTypes\ArrayObject; class User { public function __construct( public readonly int $id, public readonly string $name, ) {} } class UserArray extends ArrayObject { public function __construct(User ...$values) { parent::__construct($values); } } $users = new UserArray( new User(1, 'John'), new User(2, 'Doe'), ); foreach ($users as $user) { echo "{$user->id} => {$user->name}" . PHP_EOL; }
php examples/typedef_1.php 1 => John 2 => Doe
typedef()
It is very common that we may need to define multiple arrays for multiple classes from our project/app, to do so, we can simplify the previous example with the usage of the typedef
function
, just like this:
<?php declare(strict_types=1); include 'vendor/autoload.php'; use PHPTypes\ArrayObject; // Notice the usage of `ArrayObject` use function PHPTypes\typedef; class User { public function __construct( public readonly int $id, public readonly string $name, ) {} } typedef('array', 'User', 'UserArray'); /** * @disregard * @var ArrayObject|User[] */ $users = new UserArray( new User(1, 'John'), new User(2, 'Doe'), ); foreach ($users as $user) { echo "{$user->id} => {$user->name}" . PHP_EOL; }
php examples/typedef_2.php 1 => John 2 => Doe
Notice the usage of the @disregard
and @var
phpDoc tags to preserve the array
treatment per User
and recognize the acccess to all its properties and methods by our preferred text editor. We also conjunct the @var
type definition with the ArrayObject
type to recognize access to methods such as count
, hasAny
, isEmpty
, splice
, etc.
In case our User
class
resides inside a specific namespace
, we can specify the full path to the namespace
when calling typedef
to define the new array
inside the same namespace
:
<?php declare(strict_types=1); namespace App; include 'vendor/autoload.php'; use PHPTypes\ArrayObject; // Notice the usage of `ArrayObject` use function PHPTypes\typedef; class User { public function __construct( public readonly int $id, public readonly string $name, ) {} } typedef('array', 'App\User', 'UserArray'); /** * @disregard * @var ArrayObject|User[] */ $users = new \App\UserArray( new \App\User(1, 'John'), new \App\User(2, 'Doe'), ); foreach ($users as $user) { echo "{$user->id} => {$user->name}" . PHP_EOL; }
php examples/typedef_3.php 1 => John 2 => Doe
It is also recommended and a good practice to define custom types in a separate and dedicated file that can be accessed across our app, such as types.php