PHP: Accessors (Getters/Setters)
In languages like C# and VB.net one can define access (read/write) to class properties using accessors (get/set).
private string _name; public string name { get { return _name; } set { _name = value; } }
If we were to exclude the set accessor completely, the property becomes read-only, excluding the get accessor (obviously leaving the set accessor intact) makes the property write-only.
But more about that later, in this post we're going to talk about adding this functionality to PHP 5.
A quick way to achieve this is to simply create/use methods to get/set access to a property:
private $name; public get_name() { return $this->name; } public set_name($value) { $this->name = $value; }
This personally doesn't feel like a very "natural" way to access fields - since this involves calling methods and not assigning properties, we can however make it more natural by using "magic methods".
In the following snippet we do exactly that (magic methods __get & __set) by defining a base class containing the functionality to make this work.
abstract class GetterSetter { // Check for property accessibility protected function Accessible($name) { // Check for available accessors if ((method_exists($this, "set_$name")) || (method_exists($this, "get_$name"))) return true; // Inform dev why access to a field was denied throw new Exception((property_exists($this, $name) == false) ? "Property $name does not exist" : "Property $name not accessible"); } public function __get($name) { if ($this->Accessible($name)) { // call get accessor if (method_exists($this, "get_$name")) return $this->{"get_$name"}(); else throw new Exception("Writeonly Property $name"); } } public function __set($name, $value) { if ($this->Accessible($name)) { // call set accessor (if available) if (method_exists($this, "set_$name")) $this->{"set_$name"}($value); else throw new Exception("Readonly Property $name"); } } }
The preceding snippet automatically calls the appropriate methods (accessors), when we read/write to the property/field. To use functionality, simply extend a class.
class person extends GetterSetter { private $Age; private $Name; public $Note; // Not processed by magic get/set methods - since its public. public function __construct($Name) { $this->Name = $Name; } protected function get_Age() { return $this->Age; } protected function set_Age($value) { if ($value < 18) throw new Exception('Invalid age specified'); $this->Age = $value; } protected function get_Name() { return $this->Name; } }
Usage:
$a = new person('Jack'); //$a->Age = 10; // Throws Exception //$a->Age = 19; // Sets the field //$a->Name = "Ben"; // Throws ReadOnly exception //$a->test = 10; // Throws Exception since the field is undefined.
This ultimately provides a mechanism by which we can set constraints on class properties, e.g. field must be of certain type (int/string/bool etc), field must be in certain format (e.g. email)
Date - 2010-05-11 23:28:30
Comments - 0
PHP: Exposing web services - Part 1
Web services are useful for a number of things, e.g. we can provide companies with data without needing
to give them direct access to our databases.
One of the most important uses (in my opinion) is the interoperability it provides, which allows different
platforms, devices etc to interact with each other.
In this post we're going to expose a web service in PHP using NuSphere's Soap library,
which has been in development since 2002 - which like the name suggests relies on the SOAP protocol (XML based) and consume it in a WCF C# application.
First of all you will need to include the library and instantiate a new soap_server object, like this:
require_once("lib/nusoap.php"); $namespace = "http://www.cstruter.com"; $server = new soap_server(); $server->soap_defencoding = 'UTF-8'; $server->configureWSDL("TestService", $namespace); $server->wsdl->schemaTargetNamespace = $namespace;
It's quite important to set our soap_defencoding property to UTF-8, since this is the default encoding required by the WCF (Windows Communication Foundation)
We also need to register the functions we wish to expose against our soap_server object, like so:
$server->register('test', // function name array("name"=>"xsd:string"), // parameters array('return'=>'xsd:string'), // return value type $namespace); function test($name) { return "Hello $name"; }
Once we're done, we tell our object to handle actions sent to our script like this:
$POST_DATA = isset($GLOBALS['HTTP_RAW_POST_DATA']) ? $GLOBALS['HTTP_RAW_POST_DATA'] : @file_get_contents("php://input"); $server->service($POST_DATA);
On the C# side (using Visual Studio 2008/10), right click on your project and click on Add Service Reference.
Notice the querystring "?wsdl" circled in the image above, passed along with the url to the reference, this tells the NuSoap library to output WSDL (Web Services Description Language) - which provides C# with all the information it needs to consume the web service (something I will discuss in the next part of this post).
Using the web service in C# looks something like this:
using System; using cstruter.com.Service; // Namespace defined in the Add Service Reference dialog namespace cstruter.com { class Program { static void Main(string[] args) { TestServicePortTypeClient TestService = new TestServicePortTypeClient(); String value = TestService.test("Julie"); Console.WriteLine(value); // Outputs Hello Julie } } }
Now thats pretty much the basics to get us up and running, but what If we want to do a bit more? Like passing/returning objects from/to the web service, we need to define types, like this:
$server->wsdl->addComplexType( 'post', // Name of the object 'complexType', // Object Type (Why? Since we've got an addSimpleType method?) 'struct', // Struct /Array (Multiple objects) 'all', // Composition '', // Restriction Namespace array( 'postID' => array('name' => 'postID', 'type' => 'xsd:int'), 'Title' => array('name' => 'Title', 'type' => 'xsd:string'), 'Body' => array('Body' => 'Body', 'type' => 'xsd:string') ) // Structure Defintion );
Using the new defined object is very straightforward e.g. "tns:post":
$server->register('test2', array("name"=>"tns:post"), array('return'=>'xsd:string'), $namespace); function test2($value) { return print_r($value, true); }
On the C# side of things you will notice an auto-generated version of the object (post) we defined in our PHP script becomes available:
TestServicePortTypeClient TestService = new TestServicePortTypeClient(); post p = new post { postID = 1, Title = "Test 1 2 3", Body = "Some test" }; String value = TestService.test2(p); Console.WriteLine(value);
If we wish to pass an array of objects e.g. post[], we need to add another complexType.
$server->wsdl->addComplexType( 'posts', // Name of the object 'complexType', 'array', // Array since we're passing a set of objects '', 'SOAP-ENC:Array', array(), array( array('ref' => 'SOAP-ENC:arrayType', 'wsdl:arrayType' => 'tns:post[]') ), 'tns:post' // Child object );
In the next snippet we pass an array of posts to the web service:
$server->register('test3', array(), // Blank array if we don't have any parameters. array('return'=>'tns:posts'), // The array of objects. $namespace); function test3() { return array(array('postID'=>1, 'Title'=>'test 1', 'Body'=>'abc abc abc'), array('postID'=>2, 'Title'=>'test 2', 'Body'=>'123 123 123') ); }
And this is how we retrieve the array via C#:
TestServicePortTypeClient TestService = new TestServicePortTypeClient(); post[] ps = TestService.test3(); foreach (post p in ps) { Console.WriteLine(String.Concat(p.postID, ":", p.Title, ":", p.Body)); }
In conclusion I feel its quite a nice, simple to use library written by the guys at NuSphere. There is quite a bit more to this library, but these examples should get you on your way.
In the next part of this post we're going to have a look at the SoapServer php extension.
Date - 2010-05-06 22:30:42
Comments - 0
First 1 2 3 4 5 6 7 8 9 10 Last / 42 Pages (83 Entries)