All Projects → spatie → Typed

spatie / Typed

Licence: mit
Improvements to PHP's type system in userland: generics, typed lists, tuples and structs

Programming Languages

types
53 projects

Labels

Projects that are alternatives of or similar to Typed

truthy
Package truthy provides truthy condition testing with Go generics
Stars: ✭ 31 (-90.37%)
Mutual labels:  generics
rueidis
A Fast Golang Redis RESP3 client that supports Client Side Caching, Auto Pipelining, Generics OM, RedisJSON, RedisBloom, RediSearch, RedisAI, RedisGears, etc.
Stars: ✭ 422 (+31.06%)
Mutual labels:  generics
lru
LRU cache using go generics
Stars: ✭ 108 (-66.46%)
Mutual labels:  generics
heidi
heidi : tidy data in Haskell
Stars: ✭ 24 (-92.55%)
Mutual labels:  generics
SwiftRadix
Easily convert integers to binary/hex/octal strings and back again with clean functional syntax.
Stars: ✭ 34 (-89.44%)
Mutual labels:  generics
genx
GenX: Generics For Go, Yet Again.
Stars: ✭ 37 (-88.51%)
Mutual labels:  generics
parco
🏇🏻 generalist, fast and tiny binary parser and compiler generator, powered by Go 1.18+ Generics
Stars: ✭ 57 (-82.3%)
Mutual labels:  generics
core
The XP Framework is an all-purpose, object oriented PHP framework.
Stars: ✭ 13 (-95.96%)
Mutual labels:  generics
Stack
A Type-Safe, Thread-Safe-ish approach to CoreData in Swift
Stars: ✭ 47 (-85.4%)
Mutual labels:  generics
go2linq
Generic Go implementation of .NET's LINQ to Objects.
Stars: ✭ 41 (-87.27%)
Mutual labels:  generics
go2generics
🧪 A chunk of experiments and demos about Go 2 generics design (type parameter & type set)
Stars: ✭ 146 (-54.66%)
Mutual labels:  generics
ttlcache
An in-memory cache with item expiration and generics
Stars: ✭ 468 (+45.34%)
Mutual labels:  generics
go-inline
Generic Data Structures/Algorithms in golang.
Stars: ✭ 52 (-83.85%)
Mutual labels:  generics
ViewControllersFactory
Instantiate your ViewControllers easily with this small factory class
Stars: ✭ 26 (-91.93%)
Mutual labels:  generics
GENERIS
Versatile Go code generator.
Stars: ✭ 32 (-90.06%)
Mutual labels:  generics
generics
Deprecated! See https://github.com/golang-design/go2generics.
Stars: ✭ 26 (-91.93%)
Mutual labels:  generics
go-callbag
golang implementation of Callbag
Stars: ✭ 19 (-94.1%)
Mutual labels:  generics
GenericTableViewController
An example of Generic UITableViewController implementation
Stars: ✭ 31 (-90.37%)
Mutual labels:  generics
generics
No description or website provided.
Stars: ✭ 25 (-92.24%)
Mutual labels:  generics
generic-simd
Generic SIMD abstractions for Rust.
Stars: ✭ 45 (-86.02%)
Mutual labels:  generics

Improved PHP type system in userland

Latest Version on Packagist Build Status StyleCI Quality Score Total Downloads

This package is a mere proof of concept about what's possible in PHP's userland to improve type checking. It adds support for type inference, generics, union types, typed lists, tuples and structs. Because all is done in userland, there are limitations on what syntax is possible.

Support us

We invest a lot of resources into creating best in class open source packages. You can support us by buying one of our paid products.

We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on our contact page. We publish all received postcards on our virtual postcard wall.

Installation

You can install the package via composer:

composer require spatie/typed

Usage

Type inference

Both collections, tuples and structs support inferred types. This means that all examples are also possible, without manually specifying types. For example:

// This collection will only allow objects of type `Post` in it.
$postCollection = new Collection([new Post()]);

// This tuple will keep its signature of (Point, Point).
$vector = new Tuple(new Point(30, 5), new Point(120, 0));

// This struct's fields are autmoatically type checked.
$struct = [
    'foo' => new Post(),
    'bar' => function () {
        // ...
    },
];

The following examples all show the manual type configuration. There are some cases where type inference falls short, and you have to fall back on manually defining them. You might also prefer the manual approach, for clarity's sake.

Note that type may be partially inferred. Some fields in tuples or structs may be type definitions, others may be real values. Uninitialised types will throw an error on read.

Typed lists and collections:

$list = new Collection(T::bool());

$list[] = new Post(); // TypeError

It's possible to directly initialise a collection with data after construction.

$list = (new Collection(T::string()))->set(['a', 'b', 'c']);

This package also provides some predefined lists, as shortcuts.

$list = new IntegerList([1, 4]);

$list[] = 'a'; // TypeError

Generics:

Generic types wrap around classes, allowing you to not creating a custom type for every class.

$postList = new Collection(T::generic(Post::class));

$postList[] = 1; // TypeError

Tuples:

$point = new Tuple(T::float(), T::float());

$point[0] = 1.5;
$point[1] = 3;

$point[0] = 'a'; // TypeError
$point['a'] = 1; // TypeError
$point[10] = 1; // TypeError

Like lists, a tuple can also be given some data after construction with the set function.

$tuple = (new Tuple(T::string(), T::array()))->set('abc', []);

Structs:

$developer = new Struct([
    'name' => T::string(),
    'age' => T::int(),
    'second_name' => T::nullable(T::string()),
]);

$developer['name'] = 'Brent';
$developer['second_name'] = 'John';

$developer->set([
    'name' => 'BrenDt',
    'age' => 23,
    'second_name' => null,
]);

echo $developer->age;

$developer->name = 'Brent';

$developer->age = 'abc' // TypeError
$developer->somethingElse = 'abc' // TypeError

Nullable type

A nullable type can be defined in two, functionally identical, ways:

$list1 = new Collection(T::int()->nullable());

$list2 = new Collection(T::nullable(T::int()));

Union Type

A union type means a collection of multiple types.

$list = new Collection(T::union(T::int(), T::float()));

$list[] = 1;
$list[] = 1.1;

$list[] = 'abc'; // TypeError

Union types may also be nullable and contain generics.

What's not included:

  • Proper syntax.
  • IDE auto completion for generic types.
  • Prevention of type casting between scalar types.
  • Type hint generics in functions.

Creating your own types

The GenericType or T::generic() can be used to create structures of that type. It is, however, also possible to create your own types without generics. Let's take the example of Post. The generic approach works without adding custom types.

$postList = new Collection(T::generic(Post::class));

$postList[] = new Post();
$postList[] = 1; // TypeError 

The generic part can be skipped if you create your own type.

use Spatie\Typed\Type;
use Spatie\Typed\Types\Nullable;

class PostType implements Type
{
    use Nullable;
    
    public function validate($post): Post
    {
        return $post;
    }
}

Now you can use PostType directly:

$postList = new Collection(new PostType());

You're also free to extend the T helper.

class T extends Spatie\Typed\T
{
    public static function post(): PostType
    {
        return new PostType();
    }
}

// ...

$postList = new Collection(T::post());

The Nullable trait adds the following simple snippet, so that the type can be made nullable when used.

public function nullable(): NullType
{
    return new NullType($this);
}

Note: It's recommended to also implement __toString in your own type classes.

Extending data structures

You're free to extend the existing data structures. For example, you could make shorthand tuples like so:

class Coordinates extends Tuple
{
    public function __construct(int $x, int $y)
    {
        parent::__construct(T::int(), T::int());

        $this[0] = $x;
        $this[1] = $y;
    }
}

Why did we build this?

PHP has a very weak type system. This is simultaneously a strength and a weakness. Weak type systems offer a very flexible development platform, while strong type systems can prevent certain bugs from happening at runtime.

In its current state, PHP's type system isn't ready for some of the features many want. Take, for example, a look at some RFC's proposing changes to the current type system.

Some of those are already declined because of runtime performance issues, or implementation difficulties. This package is a thought experiment of what we could do if those features are implemented in PHP, usable with native syntax.

For example, the following syntax would be much more preferable over how this package does it.

$postList = new Collection<Post>();

// vs.

$postList[] = new Collection(T::generic(Post::class));

Anyways, it's stuff to think about. And maybe PHP's type system is fine as it is now? You can read more about type safety on my blog.

Contributing

Please see CONTRIBUTING for details.

Security

If you discover any security related issues, please email [email protected] instead of using the issue tracker.

Postcardware

You're free to use this package, but if it makes it to your production environment we highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using.

Our address is: Spatie, Kruikstraat 22, 2018 Antwerp, Belgium.

We publish all received postcards on our company website.

Credits

License

The MIT License (MIT). Please see License File for more information.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].