Easy rest service using PHP reflection api

download Easy rest service using PHP reflection api

of 21

  • date post

    27-Jan-2015
  • Category

    Technology

  • view

    114
  • download

    12

Embed Size (px)

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 of Easy rest service using PHP reflection api

  • 1. Easy Web Services using PHP reflection API phplondon, Dec 4 th2008

2. Reflection ? 3. http://www.flickr.com/photos/bcnbits/368112752/ 4. Reflection

  • In computer science, reflection is the process by which a computer program can observe and modify its own structure and behaviour.

5. Reflection in PHP5

  • reverse-engineer
  • classes,
  • interfaces,
  • exceptions
  • functions
  • Methods
  • Parameters
  • properties
  • extensions
  • retrieve doc comments for
  • functions,
  • classes and
  • methods.

6. Eg. Reflection Method class ReflectionMethod extends [] { public boolisFinal () public boolisAbstract () public boolisPublic () public boolisPrivate () public boolisProtected () public boolisStatic () public boolisConstructor () public boolisDestructor () [..] public stringgetFileName () public intgetStartLine () public intgetEndLine () public stringgetDocComment () publicarray getStaticVariables () 7. Eg. Reflection Method class Randomizer { /** *Returns randomly 0 or 1 *@returnint */ finalpublicstaticfunction get () { returnrand( 0, 1); } } //CreateaninstanceoftheReflectionMethodclass $method =new ReflectionMethod ( Randomizer ' , get' ); echo$method -> isConstructor ()? 'theconstructor' : 'aregularmethod ; printf ( "--->Documentation: %s " , var_export ( $method -> getDocComment (), 1 )); 8. 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 =newReflectionClass( 'ClassIsData' ); $properties=$reflectionClass- >getProperties(); $property ->getName();$property ->getValue($instance); 9. Reflection is useful for

  • Annotations, eg. in PHP Unit

In this example the test will fail because it doesnt throw the InvalidArgumentException 10. Easy Web Services Simple use case 11. Watch out, you will see code in slides!!! 12. classUsers { /** *@returnarray the list of all the users */ static public functiongetUsers( $limit= 10) { // each API method can have different permission requirements Access::checkUserHasPermission( 'admin' ); returnRegistry::get( 'db' )->fetchAll( " SELECT *FROM usersLIMIT $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) 13. // 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 codeFrontController::getInstance()->init();// init DB, logger, auth, etc. $request=newRequest( 'method=Users.getUsers&limit=100' ); $result=$request ->process(); How we want to call it (1/2) 14. // ResponseBuilder object can convert the data in XML, JSON, CSV // by converting your API returned value (from array, int, object, etc)$request=newRequest( '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=newRequest( 'method=Users.getUsers&token_auth=puiwrtertwoc98' ); $result=$request ->process(); How we want to call it (2/2) 15. The concept Request comes in, forwarded to Proxy that does the Reflection magic: calls the method on the right class, with the right parameters mapped. 16. classRequest{ protected$request ; function__construct( $requestString= null) { if (is_null( $requestString )) { $request=$_REQUEST ; }else{ $request= parse_str( $requestString ); } $this ->request =$request ; } functionprocess() { $responseBuilder=newResponseBuilder( $this ->request); try{ // eg. get the "Users.getUsers" $methodToCall= Helper::sanitizeInputVariable( 'method' ,$this ->request); list ( $className ,$method )= e xplode( '.' , $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=newRequest('method=Users.getUsers&limit=100' ); $result=$request ->process(); 17. classProxy { functioncall( $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=newTimer; $returnedValue= call_user_func_array(array ( $object ,$methodName ), $parameterValues ); Registry::get( 'logger_api' )->log( $className ,$methodName ,$ parameterValues $timer ->getTimeMs(), $returnedValue) ;return$returnedValue ; } functionloadClassMetadata( $className ) { $reflectionClass=newReflectionClass( $className ); foreach ( $reflectionClass ->getMethods()as$method ) { $this ->loadMethodMetadata( $className ,$method ); } } [...] } 18. 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=newRequest( ' method=Analytics.getUsers &filter_sort=name-desc &filter_search=(pattern)' ); 19. ... and use the Proxy class to generate your API documentation (from the code, and by reverse engineering your method comments) 20. Questions ? 21. 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 PHP http://www.slideshare.net/stubbles/declarative-development-using-annotations-in-php
  • Presentation under license #cc-by-sa, by Matthieu Aubry