Skip to content

Instantly share code, notes, and snippets.

@webbower
Created July 15, 2015 21:29
Show Gist options
  • Save webbower/91566df41f9788af63db to your computer and use it in GitHub Desktop.
Save webbower/91566df41f9788af63db to your computer and use it in GitHub Desktop.
PHP Classes that behave like classes from other languages
<?php
/**
* Immutable (uses ->copy() to modify instances), properties are implicitly defined by constructor signature, getting an undefined property
* throws an exception, type check instance properties, iterate over properties?...
*/
class ScalaCaseClass {
public function __construct()
{
// Somehow make it very easy to have all the arguments in the signature map to publicly accessible (faux-)instance properties
// without having to define each one on the class, so that the constructor signature implicitly defines them
}
}
/**
* Can only get and set properties with getter/setter methods (that are magically defined using __call() for anything prefixed with “get” or “set”),
* faux-static typing uses annotations to type check setFoo() data, no static methods (not sure if that can be enforced)...
*/
class JavaClass {
/**
* @var String
*/
protected $myString;
public function __call($name, array $args)
{
$action = substr($name, 0, 3);
if ($action !== ‘get’ && $action !== ’set') {
// Only works for getFoo()/setFoo() calls
// throw new BadMethodCallException();
}
$propName = lcfirst(substr($name, 3));
if(!property_exists($this, $propName)) {
// Only work for properties defined on this class
// throw new BadMethodCallException();
}
switch($action) {
case ‘get’: return $this->$propName; break;
case ‘set’: $this->$propName = $args[0]; return; break;
default: // throw new BadMethodCallException(); break;
}
}
}
/**
* Can be modified at runtime (defining methods with a method and invoking them via __call(), constructor is ClassName.new(args)?,
* sadly you can’t modify the comparison operators unless you define methods to use instead (like $foo->eq($bar) or $foo->gt($bar))
*/
class RubyClass {
// Ruby-style constructor
public static function new(…$args)
{
return new static(…$args);
}
protected function __construct(…$args)
{
// Determine how Ruby constructor args are handled and how properties are defined and get/set
}
// Potentially split out comparison methods (below) into appropriate traits
/**
* Something like:
* public function eq(MyRubyClass $that)
* {
* return true; // somehow define the method of comparison
* }
*/
// Equal
abstract public function eq(RubyClass $that);
// Not Equal
abstract public function ne(RubyClass $that);
// This is greater than that
abstract public function gt(RubyClass $that);
// This is less than that
abstract public function lt(RubyClass $that);
}
/**
* Takes any number of args in constructor and stores them internally possibly with type, access via numerical index, can simulate pattern matching?
*
*/
class Tuple {
/**
* @var [Any] - Any number of data stored in numerically-indexed positions
*/
public $data = [];
/**
* Special syntax to retrieve stored values by invoking the instance.
* $foo = new Tuple(‘foo’, 1, [‘hello’, ‘world’]);
* $bar = $foo(0); // ‘foo’
* list($blah, $sneh) = $foo(0, 2)l // [‘foo’, [‘hello’, ‘world’]]
*/
public function __invoke()
{
return func_call_user_array([$this, ‘extract’], func_get_args());
}
/**
* Extracts any stored values by their index and returns it in an array. Useful for using with list($foo, $bar, $baz) = $tuple->extract(0, 3, 4),
* or list($foo, $bar, $baz) = $tuple(0, 3, 4);
*/
public function extract(array $indexes)
{
return array_map($indexes, function($i) {
// Validate if the index exists first and throw if doesn't
return $this->data[$i];
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment