diff options
author | Emiel Bruijntjes <emiel.bruijntjes@copernica.com> | 2014-03-10 13:37:09 +0100 |
---|---|---|
committer | Emiel Bruijntjes <emiel.bruijntjes@copernica.com> | 2014-03-10 13:37:09 +0100 |
commit | dd3422f6ed454d06e6091ad5023da7fc294595b8 (patch) | |
tree | d37cc9cc541f4e6cc2fb4c1c04c704620b7151c7 | |
parent | 4872cc627642044f46ba8a8726902592a1fae05f (diff) |
splitted magic-methods-and-interfaces documentation into two seperate documentation files, added documentation about __set(), __get(), __isset() and __unset()
-rw-r--r-- | documentation/magic-interfaces.html (renamed from documentation/magic-methods-and-interfaces.html) | 40 | ||||
-rw-r--r-- | documentation/magic-methods.html | 186 |
2 files changed, 203 insertions, 23 deletions
diff --git a/documentation/magic-methods-and-interfaces.html b/documentation/magic-interfaces.html index f485805..1664e3c 100644 --- a/documentation/magic-methods-and-interfaces.html +++ b/documentation/magic-interfaces.html @@ -1,33 +1,28 @@ -<h1>Magic methods and interfaces</h1> +<h1>Magic interfaces</h1> <p> - PHP classes have a number of magic methods that you can implement to - enable special features. These are methods like __toString(), __get(), __set(), - __invoke(), etcetera. With the PHP-CPP library you can implement these - magic methods too. -</p> -<p> - Besides that, a core PHP installation also comes with a number of interfaces - that you can implement to add even more special features to a class. These + A core PHP installation comes with a number of special "magic" PHP interfaces + that script writers can implement to add special features to a class. These are interfaces with names like 'Countable', 'ArrayAccess' and 'Serializable'. The features that these interfaces bring, can also be implemented using PHP-CPP. </p> <p> - So there are magic methods and interfaces. Strangely enough, - there does not seem to be any uniformity in the Zend engine in the choice - between these magic methods and interfaces. To us it is unclear why some special features - are implemented with magic methods, while others are activated by implementing - interfaces. In our eyes the Serializable interface could just as well have - been implemented with magic __serialize() and __unserialize() methods, or the - __invoke() method could just as well have been an "Invokable" interface. - PHP is not a standardized language, and some things just seem to be the way they - are because someone felt like implementing it this way or another... + You may wonder why PHP sometimes uses <a href="magic-methods">magic methods</a> + (for example __set and __unset) and sometimes uses interfaces to change the + behavior of a class. There does not seem to be any uniformity in the choice + between these magic methods and interfaces. To us it is unclear why some + special features are implemented with magic methods, while others are activated + by implementing interfaces. In our eyes the Serializable interface could just + as well have been implemented with magic __serialize() and __unserialize() + methods, or the __invoke() method could just as well have been an "Invokable" + interface. PHP is not a standardized language, and some things just seem to be + the way they are because someone felt like implementing it this way or another... </p> <p> The PHP-CPP library tries to stay as close to PHP as possible. That's why in - your C++ classes you can also override the magic methods and implement the - special interfaces - and because C++ does not have interfaces like PHP has, - we use classes with pure virtual methods instead. + your C++ classes you can also use the special interfaces - and because C++ + does not have interfaces like PHP has, classes with pure virtual methods are + used instead. </p> <h2>Support for the SPL</h2> <p> @@ -51,8 +46,7 @@ <h2>The Countable interface</h2> <p> By implementing the Php::Countable interface, you can create objects that - can be passed to the PHP count() function. You have to implement a count() - method that returns the value that you want the count() function to return. + can be passed to the PHP count() function. </p> <p> <pre class="language-c++"><code> diff --git a/documentation/magic-methods.html b/documentation/magic-methods.html new file mode 100644 index 0000000..87c6cc2 --- /dev/null +++ b/documentation/magic-methods.html @@ -0,0 +1,186 @@ +<h1>Magic methods</h1> +<p> + Every PHP class has "magic methods". You may already know these methods + from writing PHP code: the methods start with two underscores and have + names like __set(), __isset(), __call(), etcetera. +</p> +<p> + The PHP-CPP library also has support for these magic methods. The methods + are already defined in the Php::Base class (which is the base class for + all classes that are written using the PHP-CPP library), and can be + overridden in your derived class. +</p> +<p> + The nice thing about magic methods implemented with PHP-CPP is that they + do not become visible from PHP user space. In other words, when you define + a function like __set() or __unset() in your C++ class, these functions + can not be called explicitly from PHP scripts - but they do get called + when a property is accessed. +</p> +<h2>Pseudo properties</h2> +<p> + With the methods __get(), __set(), __unset() and __isset() you can define + pseudo properties. It allows you to, for example, create read-only properties, + or properties that are checked for validity when they are set. +<p> +<p> + The magic methods work exactly the same as their counterparts in PHP scripts + do, so you can easily port PHP code that uses these properties to C++. +</p> +<p> +<pre class="language-c++"><code> +#include <phpcpp.h> + +/** + * A sample class, that has some pseudo properties that map to native types + */ +class User : public Php::Base +{ +private: + /** + * Name of the user + * @var std::string + */ + std::string _name; + + /** + * Email address of the user + * @var std::string + */ + std::string _email; + +public: + /** + * C++ constructor and C++ destructpr + */ + User() {} + virtual ~User() {} + + /** + * Get access to a property + * @param name Name of the property + * @return Value Property value + */ + virtual Php::Value __get(const Php::Value &name) override + { + // check if the property name is supported + if (name == "name") return _name; + if (name == "email") return _email; + + // property not supported, fall back on default + Php::Base::__get(name); + } + + /** + * Overwrite a property + * @param name Name of the property + * @param value New property value + */ + virtual void __set(const Php::Value &name, const Php::Value &value) override + { + // check the property name + if (name == "name") + { + // store member + _name = value; + } + + // we check emails for validity + else if (name == "email") + { + // store the email in a string + std::string email = value; + + // must have a '@' character in it + if (email.find('@') == std::string::npos) throw Php::Exception("Invalid email address"); + + // store the member + _email = email; + } + + // other properties fall back to default + else + { + // call default + Php::Base::__set(name, value); + } + } + + /** + * Check if a property is set + * @param name Name of the property + * @return bool + */ + virtual bool __isset(const Php::Value &name) override + { + // true for name and email address + if (name == "name" || name == "email") return true; + + // fallback to default + return Php::Base::__isset(name); + } + + /** + * Remove a property + * @param name Name of the property to remove + */ + virtual void __unset(const Php::Value &name) override + { + // name and email can not be unset + if (name == "name" || name == "email") throw Php::Exception("Name and email address can not be removed"); + + // fallback to default + Php::Base::__unset(name); + } +}; + +/** + * Switch to C context to ensure that the get_module() function + * is callable by C programs (which the Zend engine is) + */ +extern "C" { + /** + * Startup function that is called by the Zend engine + * to retrieve all information about the extension + * @return void* + */ + PHPCPP_EXPORT void *get_module() { + + // extension object + static Php::Extension myExtension("my_extension", "1.0"); + + // description of the class so that PHP knows + // which methods are accessible + Php::Class<User> user("User"); + + // add the class to the extension + myExtension.add(std::move(user)); + + // return the extension + return myExtension; + } +} +</code></pre> +</p> +<p> + The above example shows how you can create a User class that seems to have a + name and email property, but that does not allow you to assign an email + address without a '@' character in it, and that does not allow you to + remove the properties. +</p> +<p> +<pre code="language-php"><code> +<?php +// initialize user and set its name and email address +$user = new User(); +$user->name = "John Doe"; +$user->email = "john.doe@example.com"; + +// show the email address +echo($user->email."\n"); + +// remove the email address (this will cause an exception) +unset($user->email); +?> +</code></pre> +</p> |