Skip to content

Instantly share code, notes, and snippets.

@mrclay
Created October 22, 2012 13:27
Show Gist options
  • Save mrclay/3931502 to your computer and use it in GitHub Desktop.
Save mrclay/3931502 to your computer and use it in GitHub Desktop.
Generics in PHP experiment
<?php
require __DIR__ . '/TypedList.php';
class Foo {}
$list = new MrClay\Generics\TypedList('Foo');
/* @var Foo[] $list */
$list[] = new Foo();
$list[] = new stdClass(); // exception at run-time, but better than nothing
<?php
namespace MrClay\Generics;
use Exception;
use InvalidArgumentException;
class TypedList extends \SplDoublyLinkedList
{
/**
* @var string
*/
protected $type;
/**
* @param $type string|array
*
* @throws InvalidArgumentException
*/
public function __construct($type = null)
{
if (is_string($type)) {
$this->setType($type);
} elseif (is_array($type)) {
if (empty($type)) {
throw new InvalidArgumentException('$type cannot be empty');
}
foreach ($type as $val) {
$this->push($val);
}
} else {
throw new InvalidArgumentException('$type must be a class/interface name, or non-empty array of objects');
}
}
/**
* @param string $type
*
* @throws Exception
*/
public function setType($type)
{
if (! $this->type || ($this->type === $type)) {
$this->type = $type;
} else {
throw new Exception('Once set, type cannot be changed');
}
}
/**
* @return string
*/
public function getType()
{
return $this->type;
}
/**
* @param object $val
*
* @throws \InvalidArgumentException
*/
protected function verifyType($val)
{
if ($this->type) {
if (! $val instanceof $this->type) {
throw new InvalidArgumentException('Given value is not an instance of ' . $this->type);
}
} else {
if (!is_object($val)) {
throw new InvalidArgumentException('TypedArray can only accept objects');
}
$this->type = get_class($val);
}
}
public function push($value)
{
$this->verifyType($value);
parent::push($value);
}
public function unshift($value)
{
$this->verifyType($value);
parent::unshift($value);
}
public function offsetSet($index, $value)
{
$this->verifyType($value);
parent::offsetSet($index, $value);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment