Skip to content

Instantly share code, notes, and snippets.

@joseph-montanez
Last active March 13, 2022 01:11
Show Gist options
  • Save joseph-montanez/fa7d22e9b72cd27e62da1ac21d099174 to your computer and use it in GitHub Desktop.
Save joseph-montanez/fa7d22e9b72cd27e62da1ac21d099174 to your computer and use it in GitHub Desktop.
Tracking PHP Objects in PHP C-API

What I am trying to do is hold onto another PHP object in an internal struct. I.E:

<?php

$camera3d = new Camera3D();
$camera3d->position = new Vector3();
$camera3d->position->x++;

The reason of this is because the Camera3D struct has additional data I need to track:

// Camera, defines position/orientation in 3d space
typedef struct Camera3D {
	Vector3 position; // Camera position
	Vector3 target; // Camera target it looks-at
	Vector3 up; // Camera up vector (rotation over its axis)
	float fovy; // Camera field-of-view apperture in Y (degrees) in perspective, used as near plane width in orthographic
	int projection; // Camera projection: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC
} Camera3D;

The ideal is that when $camera3d->position is modified, I can update the internal Camera3D struct based on this tracked PHP Object.

Right now it looks like this, but attaching additional internal object in PHP is an issue:

typedef struct _php_raylib_camera3d_object {
	Camera3D camera3d;
	HashTable *prop_handler;
	php_raylib_vector3_object *position; // $camera3d->position
	php_raylib_vector3_object *target; // $camera3d->target
	php_raylib_vector3_object *up; // $camera3d->up
	zend_object std;
} php_raylib_camera3d_object;

Just for reference, this is how a getter the C code looks like:

static zend_object * php_raylib_camera2d_get_position(php_raylib_camera3d_object *obj) /* {{{ */
{
    GC_ADDREF(&obj->position->std);
    return &obj->position->std;
}
/* }}} */

This is how the setter looks like in C:

static int php_raylib_camera3d_set_position(php_raylib_camera3d_object *obj, zval *newval) /* {{{ */
{
    int ret = SUCCESS;

    if (Z_TYPE_P(newval) == IS_NULL) {
        // Cannot set this to null...
        return ret;
    }

    php_raylib_vector2_object *phpPosition = Z_VECTOR2_OBJ_P(newval);
    GC_ADDREF(&phpPosition->std);
    GC_DELREF(&obj->phpPosition->std);
    obj->position = phpPosition;

    return ret;
}
/* }}} */

When in a PHP Loop, accessing the other internal object works, but on for the first time i.e

// Update camera position for selected mode  
// RLAPI void UpdateCamera(Camera3D * camera);  
ZEND_BEGIN_ARG_INFO_EX(arginfo_UpdateCamera, 0, 1, 1)  
    ZEND_ARG_INFO(1, camera)  
ZEND_END_ARG_INFO()  
PHP_FUNCTION(UpdateCamera)  
{
    zval *camera;

    ZEND_PARSE_PARAMETERS_START(1, 1)
        Z_PARAM_ZVAL(camera)
    ZEND_PARSE_PARAMETERS_END();

    php_raylib_camera3d_object *phpCamera = Z_CAMERA3D_OBJ_P(camera);
    
    printf("UpdateCamera:camera3d position %f %f %f\n", phpCamera->position->vector3.x, phpCamera->position->vector3.y, phpCamera->position->vector3.z);

The first time this is ran, it fine. But on the second iteration, it segment vaults with an access violation.

Oddly enough, if I move the prop_handler down in the struct it then works:

	typedef struct _php_raylib_camera3d_object {
	    Camera3D camera3d;
	    php_raylib_vector3_object *position;
	    php_raylib_vector3_object *target;
	    php_raylib_vector3_object *up;
	    HashTable *prop_handler; // prop_handler moved
	    zend_object std;
	} php_raylib_camera3d_object;

However this ONLY works for accessing the PHP position object, accessing the target then gives the same access violation.

I did try to convert all the other internal objects from pointers to non-pointers:

	typedef struct _php_raylib_camera3d_object {
	    Camera3D camera3d;
	    php_raylib_vector3_object position;
	    php_raylib_vector3_object target;
	    php_raylib_vector3_object up;
	    HashTable *prop_handler; // prop_handler moved
	    zend_object std;
	} php_raylib_camera3d_object;

The application no longer crashed... While this did seem to work, internal references were completely disconnected. So the raw Camera3D values were completely separate from the attached Camera3D PHP Objects (position, target, up). For example:

<?php
UpdateCamera($camera3d); //-- should update $camera3d->position

BeginDrawing();
BeginMode3D($camera);

That above should update $camera->position vector values. It didn't. In the C-code it was assigned to the following, right :

UpdateCamera(&intern->camera3d);

phpPosition->vector3.x = intern->camera3d.position.x;
phpPosition->vector3.y = intern->camera3d.position.y;  
phpPosition->vector3.z = intern->camera3d.position.z;

I even tried to printf to ensure the values are set. The UpdateCamera did not actrually change the camera position... So I tried updating the attached PHP Object in PHP for the position vector i.e

<?php

UpdateCamera($camera3d); //-- doesn't update camera position...
$camera3d->position->x += 0.001; //--- This updates the camera position...

BeginDrawing();
BeginMode3D($camera);

This is really weird because $camera3d->position->x is not the root camera3d structure! Now granted I do the reverse assignment before UpdateCamera is called.

//....
intern->camera3d.position = phpPosition->vector3; // assigns $camera3d->position back to the internal camera position
UpdateCamera(&intern->camera3d);
phpPosition->vector3 = intern->camera3d.position; // assigns internval camera3d struct position back to $camera3d->position
//....

Youtube Video Going Over Issue

Watch the video

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment