3v4l.org

run code in 300+ PHP versions simultaneously
<?php namespace { try { $parent = new Package\MyParent(); var_dump($parent); $parent->test(); } catch (\Throwable $e) { var_dump($e); } try { $pubChild = new Package\MyParent\PublicChild();//create new public child (possible) } catch (\Throwable $e) { var_dump($e); } try { $protChild = new Package\MyParent\ProtectedChild(); //create new protected child (ERROR) } catch (\Throwable $e) { var_dump($e); } class Package { /* protect constructor so that objects can't be instantiated from outside * Since all classes inherit from Package class, they can instantiate eachother * simulating protected InnerClasses */ protected function __construct() { } /* This magic method is called everytime an inaccessible method is called * (either by visibility contrains or it doesn't exist) * Here we are simulating shared protected methods across "package" classes * This method is inherited by all child classes of Package */ public function __call($method, $args) { //class name $class = get_class($this); /* we check if a method exists, if not we throw an exception * similar to the default error */ if (method_exists($this, $method)) { /* The method exists so now we want to know if the * caller is a child of our Package class. If not we throw an exception * Note: This is a kind of a dirty way of finding out who's * calling the method by using debug_backtrace and reflection */ $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3); if (isset($trace[2])) { $ref = new ReflectionClass($trace[2]['class']); if ($ref->isSubclassOf(__CLASS__)) { return $this->$method($args); } } throw new RuntimeException("Call to private method $class::$method()"); } else { throw new RuntimeException("Call to undefined method $class::$method()"); } } } } namespace Package { class MyParent extends \Package { public $publicChild; protected $protectedChild; public function __construct() { //instantiate public child inside parent $this->publicChild = new \Package\MyParent\PublicChild(); //instantiate protected child inside parent $this->protectedChild = new \Package\MyParent\ProtectedChild(); } public function test(): void { echo "Call from parent -> "; $this->publicChild->protectedMethod(); $this->protectedChild->protectedMethod(); echo "<br>Siblings<br>"; $this->publicChild->callSibling($this->protectedChild); } } } namespace Package\MyParent { class PublicChild extends \Package { //Makes the constructor public, hence callable from outside public function __construct() { } protected function protectedMethod(): void { echo "I'm " . get_class($this) . " protected method<br>"; } protected function callSibling($sibling): void { echo "Call from " . get_class($this) . " -> "; $sibling->protectedMethod(); } } class ProtectedChild extends \Package { protected function protectedMethod(): void { echo "I'm " . get_class($this) . " protected method<br>"; } protected function callSibling($sibling): void { echo "Call from " . get_class($this) . " -> "; $sibling->protectedMethod(); } } }
Output for git.master_jit, git.master, rfc.property-hooks
object(Package\MyParent)#1 (2) { ["publicChild"]=> object(Package\MyParent\PublicChild)#2 (0) { } ["protectedChild":protected]=> object(Package\MyParent\ProtectedChild)#3 (0) { } } Call from parent -> object(RuntimeException)#4 (7) { ["message":protected]=> string(70) "Call to private method Package\MyParent\PublicChild::protectedMethod()" ["string":"Exception":private]=> string(0) "" ["code":protected]=> int(0) ["file":protected]=> string(9) "/in/KiegX" ["line":protected]=> int(61) ["trace":"Exception":private]=> array(2) { [0]=> array(6) { ["file"]=> string(9) "/in/KiegX" ["line"]=> int(87) ["function"]=> string(6) "__call" ["class"]=> string(7) "Package" ["type"]=> string(2) "->" ["args"]=> array(2) { [0]=> string(15) "protectedMethod" [1]=> array(0) { } } } [1]=> array(6) { ["file"]=> string(9) "/in/KiegX" ["line"]=> int(7) ["function"]=> string(4) "test" ["class"]=> string(16) "Package\MyParent" ["type"]=> string(2) "->" ["args"]=> array(0) { } } } ["previous":"Exception":private]=> NULL } object(Error)#7 (7) { ["message":protected]=> string(58) "Call to protected Package::__construct() from global scope" ["string":"Error":private]=> string(0) "" ["code":protected]=> int(0) ["file":protected]=> string(9) "/in/KiegX" ["line":protected]=> int(17) ["trace":"Error":private]=> array(0) { } ["previous":"Error":private]=> NULL }

This tab shows result from various feature-branches currently under review by the php developers. Contact me to have additional branches featured.

Active branches

Archived branches

Once feature-branches are merged or declined, they are no longer available. Their functionality (when merged) can be viewed from the main output page


preferences:
54.77 ms | 405 KiB | 8 Q