Last active
December 13, 2018 15:26
-
-
Save AmyStephen/4693855 to your computer and use it in GitHub Desktop.
Example Proxy Pattern implementation in PHP. The example implements an HTTP Proxy using cURL. Try it out on a local server by downloading and opening the page in your browser.
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 | |
/** | |
* @package Design Patterns | |
* @copyright 2013 Amy Stephen. All rights reserved. | |
* @license MIT | |
* | |
* Proxy Pattern | |
* | |
* A proxy pattern creates an entry point which interacts behind the scenes with other objects. | |
* Can be useful for implementing access control, to implement lazy loading of resource intensive | |
* objects, or to simply act as a wrapper to reduce the options available to another more complex object | |
*/ | |
interface HttpInterface | |
{ | |
public function get(); | |
} | |
/** | |
* HttpProxy Usage Instructions: | |
* | |
* $proxy = new HttpProxy('http://rss.cnn.com/rss/cnn_world.rss'); | |
* echo $proxy->get(); | |
* | |
*/ | |
class HttpProxy implements HttpInterface | |
{ | |
protected $address; | |
protected $string; | |
/** | |
* Constructor | |
* | |
* @param $address | |
*/ | |
public function __construct($address) | |
{ | |
$this->address = filter_var($address, FILTER_SANITIZE_URL); | |
} | |
/** | |
* Method uses HTTP address to retrieve contents of the page | |
* | |
* @return mixed | |
* @throws Exception | |
*/ | |
public function get() | |
{ | |
$handle = curl_init(); | |
curl_setopt($handle, CURLOPT_URL, $this->address); | |
curl_setopt($handle, CURLOPT_RETURNTRANSFER, 1); | |
curl_setopt($handle, CURLOPT_HEADER, 0); | |
try { | |
$data = curl_exec($handle); | |
$response = curl_getinfo($handle); | |
if ($response['http_code'] == 200) { | |
} else { | |
throw new Exception; | |
} | |
curl_close($handle); | |
} catch (Exception $e) { | |
throw new Exception ('Request for address: ' . $this->address . ' failed.'); | |
} | |
$this->string = $data; | |
return $this->__toString(); | |
} | |
/** | |
* Format output as a string | |
* | |
* @return string | |
*/ | |
public function __toString() | |
{ | |
return $this->string; | |
} | |
} | |
/** | |
* Try the Proxy Pattern Example: | |
* | |
* 1. Download and place file on your local server. | |
* 2. Open the file using your browser. | |
*/ | |
$proxy = new HttpProxy('http://www.youtube.com/watch?v=oHg5SJYRHA0'); | |
echo $proxy->get(); |
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
Agree - removed unnecessary comments from above. |
This is not a Proxy. A proxy delegates to a subject just like a decorator, with the only difference that proxies are often connecting to a different boundary like a database or remote call or used for lazy loading.
Like:
class LazySoapClient extends SoapClient
{
protected $constructor, $subject;
public function __construct($wsdl, array $options = null)
{
$this->constructor = func_get_args();
}
protected function _getSubject()
{
if(!$this->subject)
{
$this->subject = new SoapClient(...$this->constructor);
}
return $this->subject;
}
public function __call($function_name, $arguments)
{
return $this->_getSubject()->__call(...func_get_args());
}
public function __soapCall($function_name, array $arguments, array $options = null, $input_headers = null, array &$output_headers = null)
{
return $this->_getSubject()->__soapCall(...func_get_args());
}
//... other methods that forward to the subject, left out for example
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Agree on the "overkill" for comments. I rarely use comments in the body of the code although I am diligent to provide a decent docblock comment. It's too easy to copy and paste, rarely updated, never tested, and the code should be simple enough to document itself.
In this example case, however, I wanted to leave learners links if they wanted to pick up more about cURL since my example was so basic.
As far as the NOT recommendation, I am of the camp who believe it's best to code "positive."
I don't buy into the "avoid the else" thinking or conserving space. I agree with those who believe the IF portion should represent the "nominal case" but I will think about how to express the normal case in a positive way.
The example we are talking about is simple either way but when the logic starts to get complex, it is very easy to create a bug combining NOT's with OR's and compound logic.
Thanks so much for your comments!