summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--documentation/constructors-and-destructors.html8
-rw-r--r--documentation/properties.html272
-rw-r--r--include/class.h12
-rw-r--r--include/classbase.h13
-rw-r--r--src/classbase.cpp61
-rw-r--r--src/property.h100
6 files changed, 431 insertions, 35 deletions
diff --git a/documentation/constructors-and-destructors.html b/documentation/constructors-and-destructors.html
index d7cc61b..399367a 100644
--- a/documentation/constructors-and-destructors.html
+++ b/documentation/constructors-and-destructors.html
@@ -135,10 +135,10 @@ extern "C" {
// description of the class so that PHP knows which methods are accessible
Php::Class<Counter> counter("Counter");
- counter.method("__construct", &Counter::__construct);
- counter.method("increment", &Counter::increment);
- counter.method("decrement", &Counter::decrement);
- counter.method("value", &Counter::value);
+ counter.method("__construct", &Counter::__construct);
+ counter.method("increment", &Counter::increment);
+ counter.method("decrement", &Counter::decrement);
+ counter.method("value", &Counter::value);
// add the class to the extension
myExtension.add(std::move(counter));
diff --git a/documentation/properties.html b/documentation/properties.html
index bdbdfa7..30368cc 100644
--- a/documentation/properties.html
+++ b/documentation/properties.html
@@ -2,22 +2,274 @@
<p>
When you define a class completely in PHP, you can add properties (member
variables) to it. When you add member variables to a native C++ class however,
- you better use regular C++ member variables for that, instead of PHP variables.
+ you better use regular native member variables for that, instead of PHP variables.
Native variables have an immensely better performance than PHP variables,
and it would be insane to store integers or strings in Php::Value objects
if you can store them in int's and std::string objects as well.
</p>
+<h2 id="normal-members">Normal member variables</h2>
<p>
- To access these member variables you could create getX() and setX()
- methods, or alternatively implement __get() and __set() methods if you
- want to make your native member variables look like public or protected
- properties.
+ It is difficult to imagine that someone in the world would like to create
+ a native class, with regular non-typed public PHP properties on it. However,
+ if you insist, you can use the PHP-CPP library for this. Let's take an example
+ class in PHP, and see what it will look like in C++.
</p>
<p>
- I can not imagine that there is anyone in the world who would like to create
- a native class, with regular public PHP properties on it. But still, in this
- article we explain how you can do that.
+<pre class="language-php"><code>
+&lt?php
+/**
+ * PHP example class
+ */
+class Example
+{
+ /**
+ * Define a public property
+ */
+ public $property1;
+
+ /**
+ * Constructor
+ */
+ public function __construct()
+ {
+ // initialize the property
+ $this->property1 = "xyz";
+ }
+
+ /**
+ * Example method
+ */
+ public function method()
+ {
+ // do something with the public property (like changing it)
+ $this->property = "abc";
+ }
+}
+
+// create an instance
+$example = new Example();
+
+// overwrite the public property
+$example->property1 = "new value";
+
+?&gt;
+</code></pre>
</p>
<p>
- ... this article is not finished yet
-</p> \ No newline at end of file
+ The above example creates a class with one public property. This property
+ can be accessed by the Example class, but because it is public, also by
+ everyone else, as is shown in the example. If you like such classes, you can
+ write something similar with PHP-CPP.
+</p>
+<p>
+<pre class="language-cpp"><code>
+#include &lt;phpcpp.h&gt;
+
+/**
+ * C++ Example class
+ */
+class Example : public Php::Base
+{
+public:
+ /**
+ * c++ constructor
+ */
+ Example() {}
+
+ /**
+ * c++ destructor
+ */
+ virtual ~Example() {}
+
+ /**
+ * php "constructor"
+ * @param params
+ */
+ void __construct()
+ {
+ // get self reference as Php::Value object
+ Php::Value self(this);
+
+ // initialize a public property
+ self["property1"] = "xyz";
+ }
+
+ /**
+ * Example method
+ */
+ void method()
+ {
+ // get self reference as Php::Value object
+ Php::Value self(this);
+
+ // overwrite the property
+ self["property1"] = "abc";
+ }
+};
+
+/**
+ * Switch to C context so that the get_module() function can be
+ * called by C programs (which the Zend engine is)
+ */
+extern "C" {
+ /**
+ * Startup function for the extension
+ * @return void*
+ */
+ PHPCPP_EXPORT void *get_module() {
+ // create static extension object
+ static Php::Extension myExtension("my_extension", "1.0");
+
+ // description of the class so that PHP knows which methods are accessible
+ Php::Class&lt;Example&gt; example("Example");
+
+ // register the methods
+ example.method("__construct", &amp;Example::__construct);
+ example.method("method", &amp;Example::method);
+
+ // the Example class has one public property
+ example.property("property1", "xyz", Php::Public);
+
+ // add the class to the extension
+ myExtension.add(std::move(example));
+
+ // return the extension
+ return myExtension;
+ }
+}
+</code></pre>
+</p>
+<p>
+ The example code shows how you need to initialize the properties inside
+ the get_module() function.
+</p>
+<p>
+ Instead of public properties, you can also define private or protected
+ properties, but even that is probably not what you want, as storing
+ data in native C++ variables is much faster.
+</p>
+<h2>Smart properties</h2>
+<p>
+ With the <a href="magic-methods">magic methods __get() and __set()</a> you
+ can make more advanced properties that are directly mapped to your C++
+ code, and that allows you to perform additional checks when a property
+ is overwritten, so that an object always remains in a valid state.
+</p>
+<p>
+ On top of that, with the PHP-CPP library you can also assign getter and
+ setter methods to properties. Every time a property is accessed, your getter
+ or setter method will automatically be accessed.
+</p>
+<p>
+<pre class="language-cpp"><code>
+#include &lt;phpcpp.h&gt;
+
+/**
+ * C++ Example class
+ */
+class Example : public Php::Base
+{
+private:
+ /**
+ * Example property 1
+ * @var int
+ */
+ int _value = 0;
+
+
+public:
+ /**
+ * c++ constructor
+ */
+ Example() {}
+
+ /**
+ * c++ destructor
+ */
+ virtual ~Example() {}
+
+ /**
+ * Method to get access to the property
+ * @return Php::Value
+ */
+ Php::Value getValue() const
+ {
+ return _value;
+ }
+
+ /**
+ * Method to overwrite the property
+ * @param value
+ */
+ void setValue(const Php::Value &amp;value)
+ {
+ // overwrite property
+ _value = value;
+
+ // sanity check: the value should never exceed 100
+ if (_value > 100) _value = 100;
+ }
+
+ /**
+ * Method to retrieve the double property value
+ * @return Php::Value
+ */
+ Php::Value getDouble() const
+ {
+ return _value * 2;
+ }
+};
+
+/**
+ * Switch to C context so that the get_module() function can be
+ * called by C programs (which the Zend engine is)
+ */
+extern "C" {
+ /**
+ * Startup function for the extension
+ * @return void*
+ */
+ PHPCPP_EXPORT void *get_module() {
+ // create static extension object
+ static Php::Extension myExtension("my_extension", "1.0");
+
+ // description of the class so that PHP knows which methods are accessible
+ Php::Class&lt;Example&gt; example("Example");
+
+ // register the "value" property, with the methods to get and set it
+ example.property("value", &amp;Example::getValue, &amp;Example::setValue);
+
+ // register a read-only "double" property, with a method to get it
+ example.property("double", &amp;Example::getDouble);
+
+ // add the class to the extension
+ myExtension.add(std::move(example));
+
+ // return the extension
+ return myExtension;
+ }
+}
+</code></pre>
+</p>
+<p>
+ The following PHP script uses this. It created an example object, sets the
+ value property to 500 (which is not allowed, values higher than 100 are
+ rounded to 100), and then it reads out the double value.
+</p>
+<p>
+<pre class="language-php"><code>
+&lt?php
+// create object
+$object = new Example();
+
+// set the value
+$object->value = 500;
+
+// show the double value
+echo($object->double."\n");
+
+// update the double value
+// (this will trigger an error, this is a read-only property)
+$object->double = 300;
+?&gt;
+</code></pre>
diff --git a/include/class.h b/include/class.h
index d867699..23c39e1 100644
--- a/include/class.h
+++ b/include/class.h
@@ -170,12 +170,12 @@ public:
* @param getter The getter method
* @param setter The setter method
*/
- void property(const char *name, Value (T::*getter)() ) { ClassBase::property(name, static_cast<getter_callback>(getter), nullptr); }
- void property(const char *name, Value (T::*getter)() const ) { ClassBase::property(name, static_cast<getter_callback>(getter), nullptr); }
- void property(const char *name, Value (T::*getter)() , void (T::*setter)(const Value &value) ) { ClassBase::property(name, static_cast<getter_callback>(getter), static_cast<setter_callback>(setter)); }
- void property(const char *name, Value (T::*getter)() const, void (T::*setter)(const Value &value) ) { ClassBase::property(name, static_cast<getter_callback>(getter), static_cast<setter_callback>(setter)); }
- void property(const char *name, Value (T::*getter)() , void (T::*setter)(const Value &value) const) { ClassBase::property(name, static_cast<getter_callback>(getter), static_cast<setter_callback>(setter)); }
- void property(const char *name, Value (T::*getter)() const, void (T::*setter)(const Value &value) const) { ClassBase::property(name, static_cast<getter_callback>(getter), static_cast<setter_callback>(setter)); }
+ void property(const char *name, Value (T::*getter)() ) { ClassBase::property(name, static_cast<getter_callback_0>(getter)); }
+ void property(const char *name, Value (T::*getter)() const ) { ClassBase::property(name, static_cast<getter_callback_1>(getter)); }
+ void property(const char *name, Value (T::*getter)() , void (T::*setter)(const Value &value) ) { ClassBase::property(name, static_cast<getter_callback_0>(getter), static_cast<setter_callback_0>(setter)); }
+ void property(const char *name, Value (T::*getter)() const, void (T::*setter)(const Value &value) ) { ClassBase::property(name, static_cast<getter_callback_1>(getter), static_cast<setter_callback_0>(setter)); }
+ void property(const char *name, Value (T::*getter)() , void (T::*setter)(const Value &value) const) { ClassBase::property(name, static_cast<getter_callback_0>(getter), static_cast<setter_callback_1>(setter)); }
+ void property(const char *name, Value (T::*getter)() const, void (T::*setter)(const Value &value) const) { ClassBase::property(name, static_cast<getter_callback_1>(getter), static_cast<setter_callback_1>(setter)); }
private:
/**
diff --git a/include/classbase.h b/include/classbase.h
index 3ae8568..40f3fda 100644
--- a/include/classbase.h
+++ b/include/classbase.h
@@ -54,8 +54,10 @@ typedef Value (Base::*method_callback_7)(Parameters &) const;
/**
* Signatures for getters and setters
*/
-typedef Value (Base::*getter_callback)();
-typedef void (Base::*setter_callback)(const Php::Value &value);
+typedef Value (Base::*getter_callback_0)();
+typedef Value (Base::*getter_callback_1)() const;
+typedef void (Base::*setter_callback_0)(const Php::Value &value);
+typedef void (Base::*setter_callback_1)(const Php::Value &value) const;
/**
* Forward declarations
@@ -284,7 +286,12 @@ protected:
* @param getter Getter method
* @param setter Setter method
*/
- void property(const char *name, const getter_callback &getter, const setter_callback &setter);
+ void property(const char *name, const getter_callback_0 &getter);
+ void property(const char *name, const getter_callback_1 &getter);
+ void property(const char *name, const getter_callback_0 &getter, const setter_callback_0 &setter);
+ void property(const char *name, const getter_callback_1 &getter, const setter_callback_0 &setter);
+ void property(const char *name, const getter_callback_0 &getter, const setter_callback_1 &setter);
+ void property(const char *name, const getter_callback_1 &getter, const setter_callback_1 &setter);
private:
/**
diff --git a/src/classbase.cpp b/src/classbase.cpp
index 1773890..09850a7 100644
--- a/src/classbase.cpp
+++ b/src/classbase.cpp
@@ -1686,15 +1686,74 @@ void ClassBase::property(const char *name, double value, int flags)
* Set property with callbacks
* @param name Name of the property
* @param getter Getter method
+ */
+void ClassBase::property(const char *name, const getter_callback_0 &getter)
+{
+ // add property
+ _properties[name] = std::make_shared<Property>(getter);
+}
+
+/**
+ * Set property with callbacks
+ * @param name Name of the property
+ * @param getter Getter method
+ */
+void ClassBase::property(const char *name, const getter_callback_1 &getter)
+{
+ // add property
+ _properties[name] = std::make_shared<Property>(getter);
+}
+
+/**
+ * Set property with callbacks
+ * @param name Name of the property
+ * @param getter Getter method
+ * @param setter Setter method
+ */
+void ClassBase::property(const char *name, const getter_callback_0 &getter, const setter_callback_0 &setter)
+{
+ // add property
+ _properties[name] = std::make_shared<Property>(getter,setter);
+}
+
+/**
+ * Set property with callbacks
+ * @param name Name of the property
+ * @param getter Getter method
+ * @param setter Setter method
+ */
+void ClassBase::property(const char *name, const getter_callback_1 &getter, const setter_callback_0 &setter)
+{
+ // add property
+ _properties[name] = std::make_shared<Property>(getter,setter);
+}
+
+/**
+ * Set property with callbacks
+ * @param name Name of the property
+ * @param getter Getter method
* @param setter Setter method
*/
-void ClassBase::property(const char *name, const getter_callback &getter, const setter_callback &setter)
+void ClassBase::property(const char *name, const getter_callback_0 &getter, const setter_callback_1 &setter)
{
// add property
_properties[name] = std::make_shared<Property>(getter,setter);
}
/**
+ * Set property with callbacks
+ * @param name Name of the property
+ * @param getter Getter method
+ * @param setter Setter method
+ */
+void ClassBase::property(const char *name, const getter_callback_1 &getter, const setter_callback_1 &setter)
+{
+ // add property
+ _properties[name] = std::make_shared<Property>(getter,setter);
+}
+
+
+/**
* End namespace
*/
}
diff --git a/src/property.h b/src/property.h
index 589b58c..f0fd46f 100644
--- a/src/property.h
+++ b/src/property.h
@@ -22,13 +22,31 @@ private:
* The getter
* @var getter_callback
*/
- getter_callback _getter = nullptr;
+ union {
+ getter_callback_0 g0;
+ getter_callback_1 g1;
+ } _getter;
/**
* The setter
* @var setter_callback
*/
- setter_callback _setter = nullptr;
+ union {
+ setter_callback_0 s0;
+ setter_callback_1 s1;
+ } _setter;
+
+ /**
+ * Type of getter
+ * @var char
+ */
+ int _gtype = 0;
+
+ /**
+ * Type of setter
+ * @var char
+ */
+ int _stype = 100;
public:
/**
@@ -36,20 +54,77 @@ public:
* @param getter
* @param setter
*/
- Property(const getter_callback &getter, const setter_callback &setter) :
- _getter(getter), _setter(setter) {}
-
+ Property(const getter_callback_0 &getter) : _gtype(0)
+ {
+ _getter.g0 = getter;
+ }
+
+ /**
+ * Constructor
+ * @param getter
+ * @param setter
+ */
+ Property(const getter_callback_1 &getter) : _gtype(1)
+ {
+ _getter.g1 = getter;
+ }
+
+
+ /**
+ * Constructor
+ * @param getter
+ * @param setter
+ */
+ Property(const getter_callback_0 &getter, const setter_callback_0 &setter) : _gtype(0), _stype(0)
+ {
+ _getter.g0 = getter;
+ _setter.s0 = setter;
+ }
+
+ /**
+ * Constructor
+ * @param getter
+ * @param setter
+ */
+ Property(const getter_callback_1 &getter, const setter_callback_0 &setter) : _gtype(1), _stype(0)
+ {
+ _getter.g1 = getter;
+ _setter.s0 = setter;
+ }
+
+ /**
+ * Constructor
+ * @param getter
+ * @param setter
+ */
+ Property(const getter_callback_0 &getter, const setter_callback_1 &setter) : _gtype(0), _stype(1)
+ {
+ _getter.g0 = getter;
+ _setter.s1 = setter;
+ }
+
+ /**
+ * Constructor
+ * @param getter
+ * @param setter
+ */
+ Property(const getter_callback_1 &getter, const setter_callback_1 &setter) : _gtype(1), _stype(1)
+ {
+ _getter.g1 = getter;
+ _setter.s1 = setter;
+ }
+
/**
* Copy constructor
* @param that
*/
Property(const Property &that) :
- _getter(that._getter), _setter(that._setter) {}
+ _getter(that._getter), _setter(that._setter), _gtype(that._gtype), _stype(that._stype) {}
/**
* Destructor
*/
- virtual ~Property();
+ virtual ~Property() {}
/**
* Get the property
@@ -58,7 +133,8 @@ public:
*/
Value get(Base *base)
{
- return (base->*_getter)();
+ if (_gtype == 0) return (base->*_getter.g0)();
+ else return (base->*_getter.g1)();
}
/**
@@ -69,9 +145,11 @@ public:
*/
bool set(Base *base, const Value &value)
{
- if (!_setter) return false;
- (base->*_setter)(value);
- return false;
+ switch (_stype) {
+ case 0: (base->*_setter.s0)(value); return true;
+ case 1: (base->*_setter.s1)(value); return true;
+ default: return false;
+ }
}
};