Milko Kosturkov
An experienced developer specializing in the web.
Output:
{ a: 1, b: 2 }
Output:
Array
(
[a] => 1
[b] => 2
)
var o1 = {
a: 1,
b: 2
};
console.log(o1);
$o1 = [
'a' => 1,
'b' => 2
];
print_r($o1);
stdClass Object
(
[a] => 1
[b] => 2
)
$o1 = (object)[
'a' => 1,
'b' => 2
];
print_r($o1);
Casting to object
Output:
{ a: 1, b: 2 }
Output:
stdClass Object
(
[a] => 1
[b] => 2
)
var o1 = new Object();
o1.a = 5;
o1.b = 6;
console.log(o1);
$o1 = new stdClass();
$o1->a = 5;
$o1->b = 6;
print_r($o1);
Output:
Hello, World!
Output:
PHP Fatal error: Uncaught Error: Call to undefined method stdClass::a() in /home/milko/work/private/jsphp-presentation/example.php:6
Stack trace:
#0 {main}
thrown in /home/milko/work/private/jsphp-presentation/example.php on line 6
var o1 = {};
o1.func = function (someArg) {
console.log(someArg);
};
o1.func('Hello, World!');
$o1 = new stdClass();
$o1->func = function ($someArg) {
print_r($someArg);
};
$o1->func('Hello, World!');
Note:
($o1->func)('Hello, World!');
will work!
class JSObject {
public function __call($name, $arguments) {
if ($this->$name instanceof Closure) {
return call_user_func_array($this->$name, $arguments);
}
throw new NotAFunctionException("{$this->$name} is not a function!");
}
}
class NotAFunctionException extends Exception {};
Output:
Hello, World!
Output:
Hello, World!
var o1 = {};
o1.func = function (someArg) {
console.log(someArg);
};
o1.func('Hello, World!');
$o1 = new JSObject();
$o1->func = function ($someArg) {
print_r($someArg);
};
$o1->func('Hello, World!');
Output:
Hello, World!The value of a is 5
Output:
PHP Fatal error: Uncaught Error: Using $this when not in object context in /home/milko/work/private/jsphp-presentation/example.php:19
Stack trace:
#0 /home/milko/work/private/jsphp-presentation/example.php(9): {closure}('Hello, World!')
#1 /home/milko/work/private/jsphp-presentation/example.php(21): JSObject->__call('func', Array)
#2 {main}
thrown in /home/milko/work/private/jsphp-presentation/example.php on line 19
var o1 = {};
o1.a = 5;
o1.func = function (someArg) {
console.log(
someArg
+ "The value of a is "
+ this.a
);
};
o1.func('Hello, World!');
$o1 = new JSObject();
$o1->a = 5;
$o1->func = function ($someArg) {
print_r(
$someArg
. "The value of a is "
. $this->a
);
};
$o1->func('Hello, World!');
Refering to context here
class JSObject {
public function __call($name, $arguments) {
if ($this->$name instanceof Closure) {
return call_user_func_array($this->$name->bindTo($this), $arguments);
}
throw new NotAFunctionException("{$this->$name} is not a function!");
}
}
class NotAFunctionException extends Exception {};
Output:
Hello, World!The value of a is 5
Output:
Hello, World!The value of a is 5
var o1 = {};
o1.a = 5;
o1.func = function (someArg) {
console.log(
someArg
+ "The value of a is "
+ this.a
);
};
o1.func('Hello, World!');
$o1 = new JSObject();
$o1->a = 5;
$o1->func = function ($someArg) {
print_r(
$someArg
. "The value of a is "
. $this->a
);
};
$o1->func('Hello, World!');
Output:
Running constructor
Hello, World!The value of a is 5
[Function: CF1]
[Function]
Output:
A variaty of errors
function CF1(a) {
console.log('Running constructor');
this.a = a;
this.func = function (someArg) {
console.log(
someArg
+ "The value of a is "
+ this.a
);
};
}
var CF2 = function () {
console.log('Running constructor 2');
};
var o1 = new CF1(5);
o1.func('Hello, World!');
console.log(o1.constructor);
CF2();
console.log((new CF2()).constructor);
function CF1($a) {
print_r('Runninng constructor');
$this->a = $a;
$this->func = function ($someArg) {
print_r(
$someArg
. "The value of a is "
. $this->a
);
};
}
$o1 = new CF1(5);
$o1->func('Hello, World!');
print_r($o1->constructor);
print_r((new function() {})->constructor);
class JSConstructor extends JSObject {
private $__callable__;
private $__name__;
public function __construct(Closure $constructor, string $name = null) {
$this->__callable__ = $constructor;
$this->__name__ = $name;
}
public function __invoke(...$arguments) {
return call_user_func_array($this->__callable__, $arguments);
}
public function __toString() {
return sprintf('[Function%s]', is_null($this->__name__) ? '' : ': ' . $this->__name__);
}
public function newInstance(...$arguments) {
$instance = new JSObject();
$instance->constructor = $this;
call_user_func_array($this->__callable__->bindTo($instance), $arguments);
return $instance;
}
}
Output:
Running constructor
Hello, World!The value of a is 5
[Function: CF1]
[Function]
Output:
function CF1(a) {
console.log('Running constructor');
this.a = a;
this.func = function (someArg) {
console.log(
someArg
+ "The value of a is "
+ this.a
);
};
}
var CF2 = function () {
console.log('Running constructor 2');
};
var o1 = new CF1(5);
o1.func('Hello, World!');
console.log(o1.constructor);
CF2();
console.log((new CF2()).constructor);
$CF1 = new JSConstructor(function ($a) {
print_r("Runninng constructor\n");
$this->a = $a;
$this->func = function ($someArg) {
print_r(
$someArg
. "The value of a is "
. $this->a . "\n"
);
};
}, 'CF1');
$CF2 = new JSConstructor(function () {
print_r("Running constructor 2\n");
});
$o1 = $CF1->newInstance(5);
$o1->func('Hello, World!');
echo $o1->constructor . "\n";
$CF2();
echo $CF2->newInstance()->constructor;
Running constructor
Hello, World!The value of a is 5
[Function: CF1]
[Function]
Output:
5
This is proto
Context is c2
Output:
var proto = {
a: 5,
context: 'c1',
fn: function () {
console.log('This is proto');
console.log('Context is ' + this.context);
}
};
var obj = {
context: 'c2'
};
obj.__proto__ = proto;
console.log(obj.a);
obj.fn();
$proto = new JSObject();
$proto->a = 5;
$proto->context = 'c1';
$proto->fn = function () {
echo "This is proto\n";
echo "Context is {$this->context}\n";
};
$obj = new JSObject();
$obj->context = 'c2';
$obj->__proto__ = $proto;
echo $obj->a . "\n";
$obj->fn();
3 'undefined property' notices and a fatal NotAFunctionException
class JSObject {
public $__proto__;
public function __call($name, $arguments) {
if ($this->$name instanceof Closure) {
return call_user_func_array($this->$name->bindTo($this), $arguments);
}
throw new NotAFunctionException("{$this->$name} is not a function!");
}
public function __get($name) {
if ($this->__proto__ instanceof JSObject) {
return $this->__proto__->$name;
}
}
}
class NotAFunctionException extends Exception {};
Output:
5
This is proto
Context is c2
Output:
var proto = {
a: 5,
context: 'c1',
fn: function () {
console.log('This is proto');
console.log('Context is ' + this.context);
}
};
var obj = {
context: 'c2'
};
obj.__proto__ = proto;
console.log(obj.a);
obj.fn();
$proto = new JSObject();
$proto->a = 5;
$proto->context = 'c1';
$proto->fn = function () {
echo "This is proto\n";
echo "Context is {$this->context}\n";
};
$obj = new JSObject();
$obj->context = 'c2';
$obj->__proto__ = $proto;
echo $obj->a . "\n";
$obj->fn();
5
This is proto
Context is c2
Output:
Calling from the other side!
true
Output:
function C1() {}
C1.prototype.fn = function () {
console.log('Calling from the other side!');
};
var obj = new C1();
obj.fn();
console.log(obj.__proto__ === C1.prototype);
$C1 = new JSConstructor(function () {});
$C1->prototype->fn = function () {
echo "Calling from the other side!\n";
};
$obj = $C1->newInstance();
$obj->fn();
print_r($obj.__proto__ === $C1.prototype);
Again, lot's of errors!
class JSConstructor extends JSObject {
private $__callable__;
private $__name__;
public $prototype;
public function __construct(Closure $constructor, string $name = null) {
$this->__callable__ = $constructor;
$this->__name__ = $name;
$this->prototype = new JSObject();
}
public function __invoke(...$arguments) {
return call_user_func_array($this->__callable__, $arguments);
}
public function __toString() {
return sprintf('[Function%s]', is_null($this->__name__) ? '' : ': ' . $this->__name__);
}
public function newInstance(...$arguments) {
$instance = new JSObject();
$instance->constructor = $this;
$instance->__proto__ = $this->prototype;
call_user_func_array($this->__callable__->bindTo($instance), $arguments);
return $instance;
}
}
Output:
Calling from the other side!
true
Output:
function C1() {}
C1.prototype.fn = function () {
console.log('Calling from the other side!');
};
var obj = new C1();
obj.fn();
console.log(obj.__proto__ === C1.prototype);
$C1 = new JSConstructor(function () {});
$C1->prototype->fn = function () {
echo "Calling from the other side!\n";
};
$obj = $C1->newInstance();
$obj->fn();
print_r($obj.__proto__ === $C1.prototype);
Calling from the other side!
true
By Milko Kosturkov