easy rest service using php reflection api
DESCRIPTION
Quick presentation of a design pattern: How to automatically expose your classes and methods in a REST service? + Presentation of PHP Reflection API.TRANSCRIPT
![Page 1: Easy rest service using PHP reflection api](https://reader033.vdocuments.site/reader033/viewer/2022051210/54c6fe314a79591c038b46f6/html5/thumbnails/1.jpg)
Easy Web Services using PHP reflection API
phplondon, Dec 4th 2008
![Page 2: Easy rest service using PHP reflection api](https://reader033.vdocuments.site/reader033/viewer/2022051210/54c6fe314a79591c038b46f6/html5/thumbnails/2.jpg)
Reflection?
![Page 3: Easy rest service using PHP reflection api](https://reader033.vdocuments.site/reader033/viewer/2022051210/54c6fe314a79591c038b46f6/html5/thumbnails/3.jpg)
http://www.flickr.com/photos/bcnbits/368112752/
![Page 4: Easy rest service using PHP reflection api](https://reader033.vdocuments.site/reader033/viewer/2022051210/54c6fe314a79591c038b46f6/html5/thumbnails/4.jpg)
ReflectionIn computer science, reflection is the
process by which a computer program can observe and modify its own structure and behaviour.
![Page 5: Easy rest service using PHP reflection api](https://reader033.vdocuments.site/reader033/viewer/2022051210/54c6fe314a79591c038b46f6/html5/thumbnails/5.jpg)
Reflection in PHP5reverse-engineer• classes, • interfaces, • exceptions• functions• Methods• Parameters• properties• extensions
retrieve doc comments for • functions, • classes and • methods.
![Page 6: Easy rest service using PHP reflection api](https://reader033.vdocuments.site/reader033/viewer/2022051210/54c6fe314a79591c038b46f6/html5/thumbnails/6.jpg)
Eg. Reflection Methodclass ReflectionMethod extends […]{ public bool isFinal() public bool isAbstract() public bool isPublic() public bool isPrivate() public bool isProtected() public bool isStatic() public bool isConstructor() public bool isDestructor()[…..] public string getFileName() public int getStartLine() public int getEndLine() public string getDocComment() public array getStaticVariables()
![Page 7: Easy rest service using PHP reflection api](https://reader033.vdocuments.site/reader033/viewer/2022051210/54c6fe314a79591c038b46f6/html5/thumbnails/7.jpg)
Eg. Reflection Methodclass Randomizer{ /** * Returns randomly 0 or 1 * @return int */ final public static function get() { return rand( 0, 1); }}
// Create an instance of the ReflectionMethod class$method = new ReflectionMethod(‘Randomizer', get');
echo $method->isConstructor() ? 'the constructor' : 'a regular method‘;printf("---> Documentation:\n %s\n", var_export($method->getDocComment(), 1));
![Page 8: Easy rest service using PHP reflection api](https://reader033.vdocuments.site/reader033/viewer/2022051210/54c6fe314a79591c038b46f6/html5/thumbnails/8.jpg)
Reflection is useful for • Why reverse engineer comments in code?
Easy to generate documentation.• Unit tests framework: mockup objects, function
test*, etc.• Automatic serializations of object: your code
defines your data, your objects can be serialized automatically, converted in JSON, etc.
$reflectionClass = new ReflectionClass('ClassIsData');$properties = $reflectionClass->getProperties();
$property->getName(); $property->getValue( $instance );
![Page 9: Easy rest service using PHP reflection api](https://reader033.vdocuments.site/reader033/viewer/2022051210/54c6fe314a79591c038b46f6/html5/thumbnails/9.jpg)
Reflection is useful for • Annotations, eg. in PHP Unit
In this example the test will fail because it doesn’t throw the InvalidArgumentException
![Page 10: Easy rest service using PHP reflection api](https://reader033.vdocuments.site/reader033/viewer/2022051210/54c6fe314a79591c038b46f6/html5/thumbnails/10.jpg)
Easy Web Services Simple use case
![Page 11: Easy rest service using PHP reflection api](https://reader033.vdocuments.site/reader033/viewer/2022051210/54c6fe314a79591c038b46f6/html5/thumbnails/11.jpg)
Watch out, you will see code in slides!!!
![Page 12: Easy rest service using PHP reflection api](https://reader033.vdocuments.site/reader033/viewer/2022051210/54c6fe314a79591c038b46f6/html5/thumbnails/12.jpg)
class Users{ /** * @return array the list of all the users */ static public function getUsers($limit = 10) { // each API method can have different permission requirements Access::checkUserHasPermission('admin'); return Registry::get('db')->fetchAll(" SELECT * FROM users LIMIT $limit"); }}
Use case: you have this class in your system:
You want this class and the public methods to be automatically available in a REST service, so you can call: http://myService.net/?module=Users.getUsers&limit=100
And get the result (eg. in XML)
![Page 13: Easy rest service using PHP reflection api](https://reader033.vdocuments.site/reader033/viewer/2022051210/54c6fe314a79591c038b46f6/html5/thumbnails/13.jpg)
// simple call to the REST API via http$users = file_get_contents( "http://service/API/" . "?method=Users.getUsers&limit=100");
// we also want to call it from within our existing php code FrontController::getInstance()->init(); // init DB, logger, auth, etc.$request = new Request('method=Users.getUsers&limit=100');$result = $request->process();
How we want to call it (1/2)
![Page 14: Easy rest service using PHP reflection api](https://reader033.vdocuments.site/reader033/viewer/2022051210/54c6fe314a79591c038b46f6/html5/thumbnails/14.jpg)
// ResponseBuilder object can convert the data in XML, JSON, CSV// by converting your API returned value (from array, int, object, etc) $request = new Request(' method=Users.getUsers &limit=100 &format=JSON');$XmlResult = $request->process();
// possible to add token_based authentication: all API methods call helper// class that checks that the token has the right permissions $request = new Request('method=Users.getUsers&token_auth=puiwrtertwoc98');$result = $request->process();
How we want to call it (2/2)
![Page 15: Easy rest service using PHP reflection api](https://reader033.vdocuments.site/reader033/viewer/2022051210/54c6fe314a79591c038b46f6/html5/thumbnails/15.jpg)
The conceptRequest comes in, forwarded to Proxy that does the Reflection magic: calls the method on the right class, with the right parameters mapped.
![Page 16: Easy rest service using PHP reflection api](https://reader033.vdocuments.site/reader033/viewer/2022051210/54c6fe314a79591c038b46f6/html5/thumbnails/16.jpg)
class Request { protected $request; function __construct($requestString = null) { if(is_null($requestString)) { $request = $_REQUEST; } else { $request = parse_str($requestString); } $this->request = $request; } function process() { $responseBuilder = new ResponseBuilder($this->request); try { // eg. get the "Users.getUsers" $methodToCall = Helper::sanitizeInputVariable('method', $this->request); list($className, $method) = explode('.',$methodToCall); $proxy = Proxy::getInstance(); $returnedValue = $proxy->call($className, $method, $this->request ); // return the response after applying standard filters, converting format,.. $response = $responseBuilder->getResponse($returnedValue); } catch(Exception $e ) { // exception is forwarded to ResponseBuilder to be converted in XML/JSON,.. $response = $responseBuilder->getResponseException( $e ); } return $response; }}
$request = new Request( 'method=Users.getUsers&limit=100');
$result = $request->process();
![Page 17: Easy rest service using PHP reflection api](https://reader033.vdocuments.site/reader033/viewer/2022051210/54c6fe314a79591c038b46f6/html5/thumbnails/17.jpg)
class Proxy{ function call($className, $methodName, $request) { $this->setContext($className, $methodName, $request); $this->loadClassMetadata(); $this->checkMethodExists(); $this->checkParametersAreSet(); $parameterValues = $this->getParametersValues(); $object = call_user_func(array($className, "getInstance")); $timer = new Timer; $returnedValue = call_user_func_array( array($object, $methodName), $parameterValues); Registry::get('logger_api')->log($className, $methodName, $parameterValues $timer->getTimeMs(),$returnedValue); return $returnedValue; } function loadClassMetadata($className) { $reflectionClass = new ReflectionClass($className); foreach($reflectionClass->getMethods() as $method) { $this->loadMethodMetadata($className, $method); } } [...]}
![Page 18: Easy rest service using PHP reflection api](https://reader033.vdocuments.site/reader033/viewer/2022051210/54c6fe314a79591c038b46f6/html5/thumbnails/18.jpg)
Conclusion• Similar pattern as FrontController / Dispatcher• One entry point to your Models. You can then add:
– Caching– Logging– Authentication
• Eg. If your app is data-centric, the ResponseBuilder could apply set of filters.You could for example specify custom filters to be apply to API calls in the RequestString:
$request = new Request(' method=Analytics.getUsers &filter_sort=name-desc &filter_search=(pattern)');
![Page 19: Easy rest service using PHP reflection api](https://reader033.vdocuments.site/reader033/viewer/2022051210/54c6fe314a79591c038b46f6/html5/thumbnails/19.jpg)
... and use the Proxy class to generate your API documentation (from the code, and by reverse engineering your method comments)
![Page 20: Easy rest service using PHP reflection api](https://reader033.vdocuments.site/reader033/viewer/2022051210/54c6fe314a79591c038b46f6/html5/thumbnails/20.jpg)
Questions?
![Page 21: Easy rest service using PHP reflection api](https://reader033.vdocuments.site/reader033/viewer/2022051210/54c6fe314a79591c038b46f6/html5/thumbnails/21.jpg)
References• This pattern is used in the open source Piwik project
http://piwik.org• View the code on
http://dev.piwik.org/svn/trunk/core/API/• How to design an API: best practises, concepts
http://piwik.org/blog/2008/01/how-to-design-an-api-best-practises-concepts-technical-aspects/
• PHP: Reflection – Manual http://uk.php.net/oop5.reflection
• Declarative Development Using Annotations In PHPhttp://www.slideshare.net/stubbles/declarative-development-using-annotations-in-php
Presentation under license #cc-by-sa, by Matthieu Aubry