Skip to content

Instantly share code, notes, and snippets.

@alexeyshockov
Created August 15, 2017 14:13
Show Gist options
  • Save alexeyshockov/4fff855faa82bf23e621fb1e2ca07365 to your computer and use it in GitHub Desktop.
Save alexeyshockov/4fff855faa82bf23e621fb1e2ca07365 to your computer and use it in GitHub Desktop.
Object set & object map in PHP
<?php
/**
*
* Object map proof of concept.
*
*/
class Map implements IteratorAggregate, ArrayAccess, Countable
{
/**
* @var SplObjectStorage
*/
protected $storage;
public function __construct(callable $hasher = null)
{
$this->storage = new SpecializedObjectStorage($hasher);
}
public function getIterator()
{
return new ObjectStorageIterator($this->storage);
}
public function offsetExists($offset)
{
return $this->storage->offsetExists($offset);
}
public function offsetGet($offset)
{
return $this->storage->offsetGet($offset);
}
public function offsetSet($offset, $value)
{
return $this->storage->offsetSet($offset, $value);
}
public function offsetUnset($offset)
{
return $this->storage->offsetUnset($offset);
}
public function count()
{
return $this->storage->count();
}
}
class ObjectStorageIterator extends IteratorIterator
{
/**
* @param SplObjectStorage $storage
*/
public function __construct(SplObjectStorage $storage)
{
parent::__construct($storage);
}
/**
* @return object
*/
public function key()
{
return $this->getInnerIterator()->current();
}
/**
* @return mixed
*/
public function current()
{
return $this->getInnerIterator()->getInfo();
}
}
// From 5.4... And object keys in Iterator are only from 5.6.
//
// spl_object_hash works like === for objects, it computes hash simply from all object fields (values).
//
class SpecializedObjectStorage extends SplObjectStorage
{
/**
* @var callable
*/
private $hasher;
/**
* @param callable $hasher
*/
public function __construct(callable $hasher = null)
{
$this->hasher = $hasher;
}
public function getHash($object)
{
if ($this->hasher) {
return call_user_func($this->hasher, $object);
} else {
return $this->calculateHash($object);
}
}
/**
* Default implementation.
*
* @param object $object
*
* @return string
*/
private function calculateHash($object)
{
$hash = spl_object_hash($object);
// TODO Rewrite to pattern maching.
if ($object instanceof DateTime) {
// Simplest value object hashing.
// TODO Specify concrete fields to serialize.
return sha1(serialize($object));
}
// TODO DateTimeZone
return $hash;
}
}
/**
* Helper. Like Java's Objects class (JDK 7). But return default function for given type (or object).
*/
class Objects
{
/**
* Useful for value objects: hash can be built from all immutable fields of that objects.
*
* isEqualTo() methods of corresponding objects should use === comparison to match algorithm of hashing.
*
* @param mixed ...$values
*
* @return int
*/
public static function hash(...$values)
{
// TODO Implement
// array - go deep.
// object:
// 1) Hashable?
// 2) Serializable? JsonSerializable?
// 3) DEFAULT. spl_object_hash()
//
// 0) NO. go deep. What about circular references?
}
}
interface Hashable
{
/**
* Object hash.
*
* @return string
*/
public function calculateHash();
}
/*
* Это вообще всё полная ошибка, как всегда... Почти. В Java hash code INT, что вводит возможность коллизии. Тут можно
* использовать SHA1, как в распределённом GIT, при длине кторого коллизии намного менее вероятны.
*/
/*
* DateTime and inherited —>getTimestamp()
* DateTimeZone
* Stringy
* *.getHash() - ?
* Тут должна быть стандартная реализация по полям как раз. Рекурсивно идти по полям и считать...
* trait стандартный тоже должен быть с этой реализацией! Точне, Objects.hash(field1, field2...) = возвращает функцию.
*/
$map = new Map();
$d1 = new DateTime();
$d2 = new DateTime();
$h1 = spl_object_hash($d1);
$h2 = spl_object_hash($d2);
// Internal object hashes are not equal.
var_dump($h1, $h2, $h1 === $h2);
// But "our" hashes are equal, because timestamp is the same. So only 1 object in the map!
$map[$d1] = "d1";
$map[$d2] = "d2";
foreach ($map as $d => $t) var_dump($d, $t);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment