<slide title="Object Factory Approach">

<blurb>
This gets quite a bit more complex than returning simple types, or even arrays. 
The first thing to do is to declare an extension-wide global class ptr along
with the methods available in this object you are creating.
</blurb>

<example fontsize="1.5em" type="c"><![CDATA[static zend_class_entry *my_class_entry_ptr;
static zend_function_entry php_my_class_functions[] = {
    PHP_FE(add,  NULL)
    PHP_FALIAS(del,           my_del,     NULL)
    PHP_FALIAS(list,          my_list,    NULL)
    {NULL, NULL, NULL}
};]]></example>

<blurb>
Next, in our module_init function we initialize and register our class definition.
</blurb>

<example fontsize="1em" type="c"><![CDATA[PHP_MINIT_FUNCTION(test) {
    zend_class_entry my_class_entry;

    INIT_CLASS_ENTRY(my_class_entry, "my_class", php_my_class_functions);
    my_class_entry_ptr = zend_register_internal_class(&my_class_entry TSRMLS_CC);
    return SUCCESS;
}]]></example>

<blurb>
And then we create our object factory function which will return an instantiated object.
</blurb>

<example fontsize="1.5em" type="c"><![CDATA[PHP_FUNCTION(my_object) {
{
    char *fn = NULL;
    int argc = ZEND_NUM_ARGS();
    int fn_len;
    long length;
    double price;
    zend_bool setting;

    if (zend_parse_parameters(argc TSRMLS_CC,
                              "sbld", &fn, &fn_len,
			      &setting, &length, &price) == FAILURE)
        return;

    object_init_ex(return_value, my_class_entry_ptr);

    add_property_stringl(return_value,
                         "filename", fn, fn_len, 1);
    add_property_bool   (return_value,
                         "toggle", setting ? 0 : 1);
    add_property_long   (return_value,
                         "length", length);
    add_property_double (return_value,
                         "price", price);
}]]></example>

<blurb>
From user space it would be called like this:
</blurb>

<example type="php"><![CDATA[<?php
  $obj = my_object();
  $obj->add(...);
?>]]></example>

<blurb>
If you want to have the more traditional class instantiation syntax and want
to have a constructor run for it.  eg.
</blurb>

<example type="php"><![CDATA[<?php
  $obj = new my_class();
?>]]></example>

<blurb>
Then create a constructor function:
</blurb>

<example fontsize="1.5em" type="c"><![CDATA[PHP_FUNCTION(my_class) {
    char *fn = NULL;
    int argc = ZEND_NUM_ARGS();
    int fn_len;
    long length;
    double price;
    zend_bool setting;

    if (zend_parse_parameters(argc TSRMLS_CC,
                              "sbld", &fn, &fn_len,
			      &setting, &length, &price) == FAILURE)
        return;

    add_property_stringl(this_ptr, "filename", fn, fn_len, 1);
    add_property_bool(this_ptr, "toggle", setting?0:1);
    add_property_long(this_ptr, "length", length);
    add_property_double(this_ptr, "price", price);
}]]></example>

<blurb>
Note the use of %this_ptr% here.
</blurb>

<blurb>
If you want to access properties from within one of the methods, you can do this:
</blurb>

<example fontsize="1.5em" type="c"><![CDATA[pval **tmp;
if(zend_hash_find(HASH_OF(this_ptr),
                  "my_property", 11, (void **)&tmp) == SUCCESS) {
    convert_to_string_ex(tmp);
    php_printf("my_property is set to %s\n", Z_STRVAL_PP(tmp));
}]]></example>

</slide>
