Skip to main content

Secondary Navigation

  • PHP Security Center
  • Blog
  • Store
  • Downloads
    • Downloads
    • Plugins
    • MyZend Account
  • Company
    • About Zend by Perforce
    • Careers at Perforce
    • Customers
    • Partners
    • Press
  • Contact
    • Contact Us
    • Request Pricing
    • Request Support
    • Subscribe
Home
Zend

Main Navigation - Mega Menu

  • Products

    Main Navigation - Mega Menu

    • ZendPHP
      PHP Runtime and Support
    • PHP LTS
      Patches for EOL PHP
    • ZendHQ
      Must-Have Extension for ZendPHP
    • Zend Server
      PHP Application Server
  • Services

    Main Navigation - Mega Menu

    • Service Overview
    • Migration Services
    • Audits
    • Custom Consulting
    • Admin as a Service
    • Zend Black Belt Services

    Services

    Innovate faster and cut risk with PHP experts from Zend Services.

    Explore Services

  • Solutions

    Main Navigation - Mega Menu

    • PHP Cloud Solutions
    • PHP Container Solutions
    • PHP Security Solutions
    • Windows Solutions
    • Hosting Provider Solutions

    Zend Solutions Cloud

    See How Zend Helps Leading Hosting Providers Keep Their Managed Sites on Secure PHP

    Read More

  • Training

    Main Navigation - Mega Menu

    • Training Overview
    • Zend PHP Certification

    Training

    Learn PHP from PHP experts with free, on-demand, and instructor led courses.

    Explore Training

  • Resources

    Main Navigation - Mega Menu

    • Explore Resources
    • Events & Webinars
    • Papers & Videos
    • Recorded Webinars
    • Blog
    Cloud Orchestration

    Orchestrating Your PHP Applications

    Watch Now
  • Support

    Main Navigation - Mega Menu

    • Explore Support
    • PHP Long-Term Support
    • Knowledgebase
    • Documentation
    • Download Software
    • Download Plugins
    • Request Support

    Support

    Submit support requests and browse self-service resources.

    Explore Support

  • Try Free
  • PHP Security Center
  • Blog
  • Store
  • Downloads

    Main Navigation - Mega Menu

    • Downloads
    • Plugins
    • MyZend Account
    • Downloads
    • Plugins
    • MyZend Account
  • Company

    Main Navigation - Mega Menu

    • About Zend by Perforce
    • Careers at Perforce
    • Customers
    • Partners
    • About Zend by Perforce
    • Careers at Perforce
    • Customers
    • Partners
  • Contact

    Main Navigation - Mega Menu

    • Contact Us
    • Request Support
    • Subscribe

TECHNICAL GUIDE

Writing PHP Extensions

Request PDF Version
Writing PHP Extensions
1. Setting up Your PHP Build Environment on Linux
2. Generating a PHP Extension Skeleton
3. Building and Installing a PHP Extension
4. Rebuilding Extensions for Production
5. Extension Skeleton File Content
6. Running PHP Extension Tests
7. Adding New Functionality
8. Basic PHP Structures
9. PHP Arrays
10. Catching Memory Leaks
11. PHP Memory Management
12. PHP References
13. Copy on Write
14. PHP Classes and Objects
15. Using OOP in our Example Extension
16. Embedding C Data into PHP Objects
17. Overriding Object Handlers
18. Answers to Common Extension Questions

12. PHP References

Usually, when you pass a parameter to function, you do it by value, and it means, the called function cannot modify it. In general, in a PHP extension you may modify a parameter passed by value, but most probably, this will lead to memory errors and crashes. In case you need to modify the argument of function (like sort() function does), it must be passed by reference. 

Passing by reference is the main use-case for php references, but they also may be used everywhere inside other data structures (e.g. element of array). 

Internally, they are represented by zval with IS_REFERENCE as type and pointer to zend_reference structure as value. As all reference-counted types, it’s inherited from the zend_refcounted structure, which defines the format of the first 64-bit word. The rest of the structure is another embedded zval.

php reference

There are few C macros to check or retrieve fields of reference zvals (and the same macros with “_P” suffix take pointers to zvals): 

  • Z_ISREF(zv) – checks if the value is a PHP reference (has type IS_REFERENCE). 
  • Z_REF(zv) – returns dependent zend_reference structure (type must be IS_REFERENCE). 
  • Z_REFVAL(zv) – returns a pointer to the referenced value (zval). 

There are also few macros for constructing references and de-referencing: 

  • ZVAL_REF(zv, ref) – initializes zval by IS_REFERENCE type and give zend_reference pointer. 
  • ZVAL_NEW_EMPTY_REF(zv) – initializes zval by IS_REFERENCE type and a new zend_reference structure. Z_REFVAL_P(zv) needs to be initialized after this call. 
  • ZVAL_NEW_REF(zv, value) – initializes zval by IS_REFERENCE type and a new zend_reference structure with a given value. 
  • ZVAL_MAKE_REF_EX(zv, refcount) – converts “zv” to PHP reference with the given reference-counter. 
  • ZVAL_DEREF(zv) – if “zv” is a reference, it’s de-referenced (a pointer to the referenced value is assigned to “zv”). 

USING PHP REFERENCES IN OUR EXAMPLE EXTENSIONS 

Let’s try to pass a reference to our test_scale() function. 

$ php -r ‘$a = 5; var_dump(test_scale([&$a], 2));’
Warning: test_scale(): unexpected argument type in Command line code on line 1
NULL

References are not supported. 

To fix this, we should just add de-referencing. 

static int do_scale(zval *return_value, zval *x, zend_long factor)
{
    ZVAL_DEREF(x);
    if (Z_TYPE_P(x) == IS_LONG) {
        RETVAL_LONG(Z_LVAL_P(x) * factor);

Now everything is fine: 

$ php -r ‘$a = 5; var_dump(test_scale([&$a], 2));’
array(1) {
    [0]=>
    int(10)
}

Let’s also convert our test_scale() to a function test_scale_ref() that won’t return any value, but will receive argument by reference and multiply the passed value in-place.

static int do_scale_ref(zval *x, zend_long factor)
{
    ZVAL_DEREF(x);
    if (Z_TYPE_P(x) == IS_LONG) {
        Z_LVAL_P(x) *= factor;
    } else if (Z_TYPE_P(x) == IS_DOUBLE) {
        Z_DVAL_P(x) *= factor;
    } else if (Z_TYPE_P(x) == IS_STRING) {
        size_t len = Z_STRLEN_P(x);
        char *p;

        ZVAL_STR(x, zend_string_safe_realloc(Z_STR_P(x), len, factor, 0, 0));
        p = Z_STRVAL_P(x) + len;
        while (--factor > 0) {
            memcpy(p, Z_STRVAL_P(x), len);
            p += len;
        }
        *p = ‘\000’;
    } else if (Z_TYPE_P(x) == IS_ARRAY) {
        zval *val;
        ZEND_HASH_FOREACH_VAL(Z_ARR_P(x), val) {
            if (do_scale_ref(val, factor) != SUCCESS) {
                return FAILURE;
            }
        } ZEND_HASH_FOREACH_END();
    } else {
        php_error_docref(NULL, E_WARNING, “unexpected argument type”);
        return FAILURE;
    }
    return SUCCESS;
}

PHP_FUNCTION(test_scale_ref)
{
    zval * x;
    zend_long factor = TEST_G(scale); // default value

    ZEND_PARSE_PARAMETERS_START(1, 2)
        Z_PARAM_ZVAL(x)
        Z_PARAM_OPTIONAL
        Z_PARAM_LONG(factor)
    ZEND_PARSE_PARAMETERS_END();

    do_scale_ref(x, factor);
}

ZEND_BEGIN_ARG_INFO(arginfo_test_scale_ref, 1)
    ZEND_ARG_INFO(1, x) // pass by reference
    ZEND_ARG_INFO(0, factor)
ZEND_END_ARG_INFO()

static const zend_function_entry test_functions[] = {
    PHP_FE(test_test1, arginfo_test_test1)
    PHP_FE(test_test2, arginfo_test_test2)
    PHP_FE(test_scale_ref, arginfo_test_scale_ref)
    PHP_FE_END
};

Testing: 

$ php -r ‘$x=5; test_scale_ref($x, 2); var_dump($x);’
int(10)
$ php -r ‘$x=5.0; test_scale_ref($x, 2);
var_dump($x);’
float(10)
$ php -r ‘$x=”5”; test_scale_ref($x, 2);
var_dump($x);’
string(2) “55”
$ php -r ‘$x=[[5]]; test_scale_ref($x,
2); var_dump($x);’
array(1) {
[0]=> array(1) {
        [0]=>
        int(10)
    }
}

Everything looks correct, but in some cases our function is going to behave incorrectly. See the next section for more details about how to avoid issues by using Copy on Write. 

Request PDF Version

Book traversal links for 12. PHP References

  • ‹ 11. PHP Memory Management
  • Writing PHP Extensions
  • 13. Copy on Write ›

Footer menu

  • Products
    • ZendPHP
    • PHP Long-Term Support
    • ZendHQ
    • Zend Server
    • Laminas Enterprise Support
    • PHP Development Tools
  • Services
    • PHP Long-Term Support
    • Migration Services
    • Audits
    • CI/CD Services
    • Custom Consulting
    • Admin as a Service
  • Free Trials and Demos
    • ZendPHP Trial
    • Zend Server Trial
    • ZendHQ Demo
  • Training
  • Resources
    • PHP Security Center
    • Papers & Videos
    • Events & Webinars
    • Recorded Webinars
    • Blog
    • Case Studies
  • Hubs
    • PHP Versions Guide
    • Developing Web Apps With PHP
    • Guide to PHP and IBM i
    • PHP Security
  • Store
  • Downloads
    • MyZend Account
    • Plugins
    • Container Registry
  • Support
    • PHP Long-term Support
    • Knowledgebase
    • Documentation
    • Software End of Life Policy
  • Contact
    • Request Pricing
    • Request Support
    • Subscribe
  • Company
    • About Zend by Perforce
    • Careers at Perforce
    • Customers
    • Partners
    • Press
Home

Zend by Perforce © Perforce Software, Inc.
Terms of Use  |  Privacy Policy | Sitemap

Social Menu

  • Facebook
  • LinkedIn
  • Twitter
  • YouTube
  • RSS
Send Feedback