1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
<?php class PropertyHandler { const GET_REGEX = "^get([aA-zZ0-9_]+)$"; const SET_REGEX = "^set([aA-zZ0-9_]+)$"; private $props; function __construct() { $props = array(); } public function __call($method, $arguments) { if($this->isGetMethod($method)) { return $this->execGetMethod($method); }elseif($this->isSetMethod($method)) { return $this->execSetMethod($method, $arguments); }else { throw new Exception("Unhandled method $method"); } } private function isGetMethod($method) { return $this->isTypeMethod($method, self::GET_REGEX); } private function isSetMethod($method) { return $this->isTypeMethod($method, self::SET_REGEX); } private function isTypeMethod($method, $regex) { return (preg_match("/$regex/", $method) > 0); } private function execGetMethod($method) { $matches = array(); preg_match("/" . self::GET_REGEX . "/", $method, $matches); if(count($matches) > 0) { return $this->getProp($matches[1]); } } private function execSetMethod($method, $arguments) { if(count($arguments) > 1) { throw new Exception("Set methods are not allowed to take more than one argument"); } $matches = array(); preg_match("/" . self::SET_REGEX . "/", $method, $matches); if(count($matches) > 0) { $this->setProp($matches[1], $arguments[0]); } } public function setProp($propName, $propVal) { if(!$propName) { throw new Exception("Invalid empty property name"); } $this->props[$propName] = $propVal; } public function getProp($propName) { if(isset($this->props[$propName])) { return $this->props[$propName]; } } } /** * Very simple example */ class PropTest extends PropertyHandler { public function __construct() { parent::__construct(); } } $props = new PropTest(); //Notice that neither PropTest nor PropertyHandler actually have setFirstName or getFirstNames //These are setting and retrieving associative the associative array value with key "FirstName" $props->setFirstName('Mark'); echo $props->getFirstName(); ?>
Refactorings
No refactoring yet !
exil.myopenid.com
September 15, 2008, September 15, 2008 22:13, permalink
Great code, but it has a lot of unnecessary overhead, since it forms the base/core class that all other classes take functionality from, this overhead will be exponential - pretty code must take a backseat here, stability and speed must be the overall implementation goal.
First I would strongly advise against such usage of regex's, and I would also re-consider breaking it down so much.
Here is my take on it, I bashed this up and tested it with your above example, using a loop to execute it 100,000 times, it took half the time - (I know its missing the getProp() function etc, but they're easily added)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
<?php /** * This class implements auto-getter and setters by making using of PHP magic __call() method.. */ class PropertyHandler { private $props; function __construct() { $props = array(); } public function __call($method, $arguments) { // Handle Setters.... if(strpos($method, "set") === 0) { $param = substr($method, 3, strlen($method)); if(!strlen($param)) { throw new Exception("Invalid or empty property name"); } if(!count($arguments)) { throw new Exception("Not allowed more than 1 argument.."); } $this->props[$param] = $arguments[0]; } // Handle Getters.... elseif(strpos($method, "get") === 0) { $param = substr($method, 3, strlen($method)); if(strlen($param) == 0) { throw new Exception("Invalid or empty property name"); } return $this->props[$param]; } // No manageable type found? thats fatal.. else { throw new Exception("Unhandled method $method"); } } } /** * Very simple example */ class PropTest extends PropertyHandler { public function __construct() { parent::__construct(); } } for($i = 0; $i < 100000; $i++) { $props = new PropTest(); $props->setFirstName('Mark'); $props->getFirstName(); } ?>
fain182.myopenid.com
November 13, 2008, November 13, 2008 11:16, permalink
it isn't better to use __get and __set?
This class lets you handle basic getting & setting of class properties without having to declare methods for each property.
All methods that start with "get" or "set" (that aren't already declared) are routed through to __call magic method and then values are set & retrieved from an associative array.