Search code examples
phpcphp-extension

Passing php-memcached object to an extension method


I am new to c extension, so please excuse if you find my question lame. I am trying to pass a php-memcached object to my custom php-extension. Can someone help me with how can I retrieve and use the object in my extension code.

A php-memcached object will be created in php and then passed to the bleow method of my extension.

My method is something like this

PHP_METHOD(Test_Ext, test_memcache) 
{
    zval *obj, *memc_link = NULL;
    memcached_st *memc;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &memc_link) == FAILURE) {
    return;
}
obj = getThis();

    //How can I use the memc_link to get the memcached_st obj ???    

}

I have tried googling but there is very less help available on the net for the same. I also looked for the php-memcached source and didn't find the struct exported which I could use by doing an include "php_memcached.h"


Solution

  • Officially you can't.

    The memcached_st is stored inside an object. You can retrieve that object from the user with the "o" modifier. As php-memcached exports the class entry you can also request the specific object.

    #include "memcached/php_memcached.h"
    
    /*...*/
    zval *memcached_object;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &memcached_object, php_memc_get_ce()) == FAILURE) {
        return;
    }
    /* ... */
    

    Then you can be sure that memcached_object holds a memcached PHP object. But you don't know what this object looks like. Unfortunately that information isn't exported. Neither is a C level API.

    If you like risk and like playing with other's private things you however can copy the object structure into your code and work with that. But be warned: That may break heavily whenever memcached maintainers decide to change their implementation in any way ... and your compiler won't be able to help you.

    So we copy the structure describing it from php_memcached.c and work with it. Note that I cut out some elements from the original. See inline comment.

    #include "memcached/php_memcached.h"
    
    typedef struct {
        zend_object zo;
    
        struct memc_obj {
            memcached_st *memc;
            zend_bool compression;
    
    #ifdef DISABLED_0
            /* Commenting these out as we don't have access to the
               enum declarations. We should not copy or create any of
               these objects as we won't know the size, but we will know
               the offset of the members above, which should be enough.
               Also we don't know if HAVE_MEMCACHED_SASL is defined so we
               know nothing about store_retry_count's offset.
            */
    
            enum memcached_serializer serializer;
            enum memcached_compression_type compression_type;
    #if HAVE_MEMCACHED_SASL
            zend_bool has_sasl_data;
    #endif
            long store_retry_count;
    #endif
        } *obj;
    
        zend_bool is_persistent;
        zend_bool is_pristine;
        int rescode;
        int memc_errno;
    } fake_php_memc_t;
    
    PHP_FUNCTION(myfunc)
    {
        zval *memcached_object;
        fake_php_memc_t *fakeobj;
        memcached_st *memc;
    
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &memcached_object, php_memc_get_ce()) == FAILURE) {
            return;
        }
    
        fakeobj = (php_memc_t *) zend_object_store_get_object(object TSRMLS_CC);
        memc = fakeobj->obj->memc;
        /* .... */
    }
    

    Note: I haven't tested this, there might be typos etc.

    Reminder: As said, be careful this builds assumptions about the insights of another extension into yours!

    Better would be to ask php-memcached maintainers to export an API with the features you need.