Skip to content

Instantly share code, notes, and snippets.

@arieh
Created October 5, 2010 11:00
Show Gist options
  • Save arieh/611358 to your computer and use it in GitHub Desktop.
Save arieh/611358 to your computer and use it in GitHub Desktop.
This class is a proof of concept of how you can use the new Closures in PHP5.3 to import JS paradigms into PHP
<?php
class JSClass{
/**
* @var array a container for all of the Class's members and methods.
*/
private $params = array();
/**
* @param array $params a list of members and methods to assign to the Class
* @access private
* @return JSClass instance
*/
private function __construct(array $params){
$this->params = $params;
return $this;
}
/**
* replaces the private constructor to make it more clear that this is a factory.
*
* @param array|JSClass $params a list of members and methods to assign to the Class
* @param array $ext a list of members and methods to use for overriding original methods (used when extending a class)
*
* @access public
* @return JSClass instance
*/
static public function generate($params,$ext=array()){
if (is_array($params))
return new JSClass($params);
if ($params instanceof JSClass){
$params = array_merge($params->params,$ext);
return new JSClass();
}
}
/**
* calls a lambda, passing it $self as 1st parameter. Similar to JS's apply
* @param Closure $callback a method to run
* @param array $params an array of parameters to pass to the function
* @access public
* @return mixed whatever the method returns
*/
public function apply($callback,$params = array()){
//$self = &amp;$this;
array_unshift($params,$this);
return call_user_func_array($callback,$params);
}
/**
* creates a new instance of the class
*
*/
public function create(){
$params = func_get_args();
$obj = new JSClass($this->params);
if (array_key_exists('init',$this->params) && is_callable($this->params['init'])){
$res = $obj->apply($this->params['init'],$params);
if ($res) return $res;//if initializer actualy returned a value
}
return $obj;
}
/**
* calls a method if exists in the parameter stack, using apply
*/
public function __call($name,$params){
$params = func_get_args(); //get all paramaters;
if (array_key_exists($name,$this->params) && is_callable($this->params[$name])){
$this->apply($this->params[$name],$params);
}
}
public function __get($name){
if (array_key_exists($name,$this->params)) return $this->params[$name];
}
public function __set($name,$value){
$this->params[$name]=$value;
}
public function __isset($name){
return array_key_exists($name,$this->params);
}
}
@arieh
Copy link
Author

arieh commented Oct 5, 2010

A simple use example can be:
$Class1 = JSClass::generate(array(
'a' => 'aaa'
, 'init' => function($self){
echo $self->a;
}
));

$ins1 = $Class1->create(); //will echo aaa

Extending a class will be:

//assuming above Class1

$parent = &$Class1;

$Class2 = JSClass::generate($Class1, array(
    'init' => function($self,$suffix) use($parent){
        $self->a='bbb';
        $self->apply($parent->init);
        echo $suffix;
    }
));

$ins2 = $Class2->create('ccc'); //will echo bbbccc

You can read more here: http://blog.arieh.co.il/posts/open/a-js-class-implementaion-for-php

@arieh
Copy link
Author

arieh commented Oct 6, 2010

creating private variables is only possible JS style:
$Class3 = call_user_func(function() use ($Class1){
//closest thing we have to self-invoking until 5.4
$private = function($self){
$self->a = 'ccc';
};

    $parent = &$Class1;

    return = JSClass::generate($Class1, array(
        'init' => function($self) use ($parent,$private){
            $self->apply($private);
            $self->apply($parent->init);
        };
    ));
});

$Class3->create(); //ccc

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment