Created
January 21, 2022 06:30
-
-
Save priyadi/9f70fc46147921cd5b5154eb888e4903 to your computer and use it in GitHub Desktop.
A wrapper to make a PHP object read only recursively.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Rekalogika\Util; | |
use Doctrine\Common\Collections\ArrayCollection; | |
use Doctrine\Common\Collections\Collection; | |
/** | |
* Make an object read only by recursively only allowing get*, is*, has* | |
* methods, and specifically for Doctrine Collection: contains, containsKey, | |
* get, getKeys, getValues, isEmpty, first, last, count. | |
* | |
* This assumes all the getter methods are really getters, and will not change | |
* the object's attributes. | |
* | |
* If the method outputs an array, it will be converted into an ArrayCollection. | |
* | |
* The intended usage is to safely feed an object as an input for Symfony | |
* Expression Language, and prevent it from being modified by the expression. | |
* | |
* @author Priyadi Iman Nurcahyo <[email protected]> | |
*/ | |
final class ReadOnly | |
{ | |
private $object; | |
const COLLECTION_ALLOW = [ | |
'contains', | |
'containsKey', | |
'get', | |
'getKeys', | |
'getValues', | |
'isEmpty', | |
'first', | |
'last', | |
'count' | |
]; | |
public function __construct($object) | |
{ | |
if (!is_object($object)) { | |
throw new \InvalidArgumentException('Input is not an object'); | |
} | |
$this->object = $object; | |
} | |
/** | |
* __call magic method | |
* | |
* @param string $method | |
* @param array $args | |
* @return mixed | |
*/ | |
public function __call(string $method, array $args) | |
{ | |
if ($this->object instanceof Collection) { | |
if (!in_array($method, self::COLLECTION_ALLOW)) { | |
throw new \BadMethodCallException('Method is blocked: ' . $method); | |
} | |
} else { | |
if (!preg_match('/^(get|is|has)[A-Z]/', $method)) { | |
throw new \BadMethodCallException('Method is blocked: ' . $method); | |
} | |
if (count($args) > 0) { | |
throw new \BadMethodCallException('Using arguments is prohibited: ' . $method); | |
} | |
} | |
$output = call_user_func_array([$this->object, $method], $args); | |
if (is_object($output)) { | |
return new self($output); | |
} elseif (is_array($output)) { | |
return new self(new ArrayCollection($output)); | |
} else { | |
return $output; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment