timetoogo/php-generics

This package is abandoned and no longer maintained. No replacement package was suggested.

Generic types for PHP

0.2.4 2014-02-12 12:02 UTC

This package is auto-updated.

Last update: 2022-12-25 03:46:22 UTC


README

Boredom and a day: Simple generics for PHP

What are generics?

Generics allows you to write type safe code against multiple types.

Installation

To install with composer add this to your composer.json:

{
    "require": {
      "timetoogo/php-generics": "0.2.4"
    }
}

The implementation

This library has taken advantage of PHP's namspacing and autoloading to emulate generic types. The generic classes are parsed, then converted into the required concrete types and stored in the configurated directory.

Getting Started

To get started with PHP-Generics must first set the following configuration:

  • DevelopmentMode - If development mode is set to true, the cached concrete types will be ignored and overwritten.
  • RootPath - The root of your project, the namespaces and class names must correspond with the directory and file paths.
  • CachePath - The path to use for storing the concrete implementations of the generic types.
$Configuration = new \Generics\Configuration();
$Configuration->SetIsDevelopmentMode(true);
$Configuration->SetRootPath(__DIR__);
$Configuration->SetCachePath(__DIR__ . '/Cache');
//Register the generic auto loader
\Generics\Loader::Register($Configuration);

All generic class files must end in .generic.php

A Generic Example

The below code demonstrate a simple generic type:

class Maybe {
    private $MaybeValue;
    
    public function __construct(__TYPE__ $Value = null) {
        $this->MaybeValue = $Value;
    }
    
    public function HasValue() {
        return $this->MaybeValue !== null;
    }
    
    public function GetValue() {
        return $this->MaybeValue;
    }
    
    public function SetValue(__TYPE__ $Value = null) {
        $this->MaybeValue = $Value;
    }
}

Note the use of the __TYPE__ magic constant, these are used as type parameters. The constant will be replaced with the concrete class type as required. You can also use multiple type parameters in the form of __TYPE1__, __TYPE2__ etc. You can use type type parameters in any context: $Var instanceof __TYPE__, func(__TYPE__), __TYPE__::Foo() etc.

Note that __TYPE__ is an alias for __TYPE1__.

Using the generic types

The type parameters of the class are defined as sub-namespaces and are seperated by a special namespace _:

Creating a concete implementation of the above generic can be done like so:

$Maybe = new Maybe\stdClass();
$Maybe->HasValue(); //false
$Maybe->SetValue(new stdClass());
$Maybe->HasValue(); //true
$Maybe->SetValue(new DateTime()); //ERROR

Below creates a Tuple with __TYPE1__ as stdClass and __TYPE2__ as DateTime:

$Tuple = new TupleOf\stdClass\_\DateTime();

Limitation: All type parameter must be fully qualified:

If you have a namespaced class Foo\Bar\SomeClass this must be specified in the generic type parameter:

$Tuple = new TupleOf\Foo\Bar\SomeClass\_\DateTime();

This creates a Tuple with __TYPE1__ as Foo\Bar\SomeClass and __TYPE2__ as DateTime.

Other uses

Generics can be used with inheritence:

class TupleOfBarAndBaz extends TupleOf\Bar\_\Baz {
    //...
}

Generic interfaces and traits are also supported:

interface IHaveOne {
    public function GetOne();
    public function SetOne(__TYPE__ $One);
}

class User implements IHaveOne\Account {
    private $One;
    
    public function GetOne(){
        return $this->One;
    }
    public function SetOne(Account $One) {
        $this->One = $One;
    }
}

Generic can be nested:

$ArrayOfArrayOfStandardClasses = new ArrayOf\ArrayOf\stdClass();

You can even extend/implement/use generic type paramerters:

class Example extends __TYPE1__ implements __TYPE2__, __TYPE3__ {
    use __TYPE4__, __TYPE5__;
}