Skip to content

Instantly share code, notes, and snippets.

@alecgorge
Created November 17, 2010 03:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alecgorge/702925 to your computer and use it in GitHub Desktop.
Save alecgorge/702925 to your computer and use it in GitHub Desktop.
How I think attributes should go down.
<?php
class WebService extends Attribute {
public $baseURI = "";
public $name = "";
public $desc = "";
public function __construct ($baseURI, $name, $desc) {
$this->baseURI = $baseURI;
$this->name = $name;
$this->desc = $desc;
}
}
class WebMethod extends Attribute {
public $uri = "";
public $name = "";
public $desc = "";
public $argDocs = array();
public function __construct ($uri, $name, $desc, $argumentDocs) {
$this->uri = $uri;
$this->name = $name;
$this->desc = $desc;
$this->argDocs = $argumentDocs;
}
}
class WebServer {
private $subclass = "";
private $serviceURI = "";
private $serviceName = "";
private $serviceDesc = "";
private $urlMapping = array();
public function __construct($subclass) {
$this->subclass = $subclass;
}
public function start () {
$r = new ReflectionClass($this->subclass);
/**
* I think getAnnotations should return an array of annotations matching the name because you should be
* able to have multiple annotations with the same name. This also uses function array dereferencing.
*
* @url http://wiki.php.net/rfc/functionarraydereferencing
*/
$classInfo = $r->getAnnotations("WebService")[0];
// I foresee $classInfo containing an instance of the WebService object
$this->serviceURI = $classInfo->baseURI;
$this->serviceName = $classInfo->name;
$this->serviceDesc = $classInfo->desc;
// now to get all the public methods (static and otherwise)
$methods = $r->getMethods();
foreach($methods as $method) {
$methodInfos = $method->getAnnotations("WebMethod");
// $methodInfo is an empty array, not null if no matches are found
if(!empty($methodInfos)) {
foreach($methodInfos as $info) {
if(!empty($this->urlMapping[$info->uri])) {
throw new Exception("URI {$this->serviceURI}{$info->uri} is already in use!");
return;
}
// binds the specified uri to the method
$this->urlMapping[$info->uri] = $method;
}
}
}
/* everything is bound, now just to parse the url and call the appropriate method
$method now equals the string from the URI that is the method and $args is the array of args.
For the url being "/api/multiply/4/5", $method = "test" and $args = array(4,5).
This is just a simple example, but you could make the attributes so they say what type
each argument needs to be, then you can validate the arguments at this point and throw
the proper exception/give an invalid argument response.
*/
if(array_key_exists($method, $this->urlMapping)) {
// This works because you can call the methods of child classes.
echo json_encode(call_user_func_array(array($this, $this->urlMapping[$method]->getName()), $args));
exit();
}
else {
throw new Exception("Method '{$method}' doesn't exist!");
}
}
}
attribute WebService("/api/", "My Web Api", "The description of my Web API");
class MyWebService extends WebServer {
public function __construct() {
parent::__construct(get_class($this));
}
// doQuery is exposed through /api/multiply
attribute WebMethod("multiply", "The query method", "The description of the query method.", array(
"Some documentation for arg1",
"Some docs for arg2"
);
public function doQuery ($x, $y) {
return $x * $y;
}
}
$server = new MyWebService();
$server->start();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment