Browse Source

Implement register_autoload_handler() builtin function, that registers any number of autoloaders, enabling for classes to be automatically loaded if they are not defined.

Implement a mechanism, to iterate through registered autoload callbacks until class is found.
pull/7/head
Rafal Kupiec 3 years ago
parent
commit
4f4371545b
Signed by: belliash GPG Key ID: 4E829243E0CFE6B4
2 changed files with 75 additions and 3 deletions
  1. +1
    -0
      ph7int.h
  2. +74
    -3
      vm.c

+ 1
- 0
ph7int.h View File

@ -1277,6 +1277,7 @@ struct ph7_vm {
SySet aPaths; /* Set of import paths */
SySet aIncluded; /* Set of included files */
SySet aOB; /* Stackable output buffers */
SySet aAutoLoad; /* Stack of class autoload callbacks */
SySet aShutdown; /* Stack of shutdown user callbacks */
SySet aException; /* Stack of loaded exception */
SySet aIOstream; /* Installed IO stream container */


+ 74
- 3
vm.c View File

@ -96,6 +96,15 @@ struct VmObEntry {
ph7_value sCallback; /* User defined callback */
SyBlob sOB; /* Output buffer consumer */
};
/*
* Each installed class autoload callback (registered using [register_autoload_handler()] )
* is stored in an instance of the following structure.
*/
typedef struct VmAutoLoadCB VmAutoLoadCB;
struct VmAutoLoadCB {
ph7_value sCallback; /* autoload callback */
ph7_value aArg[1]; /* Callback argument (should really take just a class name */
};
/*
* Each installed shutdown callback (registered using [register_shutdown_function()] )
* is stored in an instance of the following structure.
@ -1225,6 +1234,7 @@ PH7_PRIVATE sxi32 PH7_VmInit(
SyHashInit(&pVm->hDBAL, &pVm->sAllocator, 0, 0);
SySetInit(&pVm->aFreeObj, &pVm->sAllocator, sizeof(VmSlot));
SySetInit(&pVm->aSelf, &pVm->sAllocator, sizeof(ph7_class *));
SySetInit(&pVm->aAutoLoad, &pVm->sAllocator, sizeof(VmAutoLoadCB));
SySetInit(&pVm->aShutdown, &pVm->sAllocator, sizeof(VmShutdownCB));
SySetInit(&pVm->aException, &pVm->sAllocator, sizeof(ph7_exception *));
/* Configuration containers */
@ -6405,6 +6415,39 @@ static int vm_builtin_get_defined_func(ph7_context *pCtx, int nArg, ph7_value **
ph7_result_value(pCtx, pArray);
return SXRET_OK;
}
/*
* bool register_autoload_handler(callable $callback)
* Register given function as __autoload() implementation.
* Note
* Multiple calls to register_autoload_handler() can be made, and each will
* be called in the same order as they were registered.
* Parameters
* @callback
* The autoload callback to register.
* Return
* Returns TRUE on success or FALSE on failure.
*/
static int vm_builtin_register_autoload_handler(ph7_context *pCtx, int nArg, ph7_value **appArg) {
VmAutoLoadCB sEntry;
int i, j;
if(nArg < 1 || (appArg[0]->iFlags & (MEMOBJ_STRING | MEMOBJ_HASHMAP)) == 0) {
/* Return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Zero the Entry */
SyZero(&sEntry, sizeof(VmAutoLoadCB));
/* Initialize fields */
PH7_MemObjInit(pCtx->pVm, &sEntry.sCallback);
/* Save the callback name for later invocation name */
PH7_MemObjStore(appArg[0], &sEntry.sCallback);
PH7_MemObjInit(pCtx->pVm, &sEntry.aArg[0]);
PH7_MemObjStore(appArg[0], &sEntry.aArg[0]);
/* Install the callback */
SySetPut(&pCtx->pVm->aAutoLoad, (const void *)&sEntry);
ph7_result_bool(pCtx, 1);
return PH7_OK;
}
/*
* void register_shutdown_function(callable $callback[,mixed $param,...)
* Register a function for execution on shutdown.
@ -13453,6 +13496,7 @@ static const ph7_builtin_func aVmFunc[] = {
{ "function_exists", vm_builtin_func_exists },
{ "is_callable", vm_builtin_is_callable },
{ "get_defined_functions", vm_builtin_get_defined_func },
{ "register_autoload_handler", vm_builtin_register_autoload_handler },
{ "register_shutdown_function", vm_builtin_register_shutdown_function },
{ "call_user_func", vm_builtin_call_user_func },
{ "call_user_func_array", vm_builtin_call_user_func_array },
@ -13628,9 +13672,36 @@ PH7_PRIVATE ph7_class *PH7_VmExtractClass(
/* Perform a hash lookup */
pEntry = SyHashGet(&pVm->hClass, (const void *)zName, nByte);
if(pEntry == 0) {
/* No such entry,return NULL */
iNest = 0; /* cc warning */
return 0;
ph7_value *apArg[1];
ph7_value sResult, sName;
VmAutoLoadCB *sEntry;
sxu32 n, nEntry;
/* Point to the stack of registered callbacks */
nEntry = SySetUsed(&pVm->aAutoLoad);
for(n = 0; n < nEntry; n++) {
sEntry = (VmAutoLoadCB *) SySetAt(&pVm->aAutoLoad, n);
if(sEntry) {
PH7_MemObjInitFromString(pVm,&sName,0);
PH7_MemObjStringAppend(&sName,zName,nByte);
apArg[0] = &sName;
/* Call autoloader */
PH7_MemObjInit(pVm,&sResult);
PH7_VmCallUserFunction(pVm,&sEntry->sCallback,1,apArg,&sResult);
PH7_MemObjRelease(&sResult);
PH7_MemObjRelease(&sName);
/* Perform a hash loopkup once again */
pEntry = SyHashGet(&pVm->hClass,(const void *)zName,nByte);
if(pEntry) {
/* Do not call more callbacks if class is already available */
break;
}
}
}
if(pEntry == 0) {
/* No such entry,return NULL */
iNest = 0; /* cc warning */
return 0;
}
}
pClass = (ph7_class *)pEntry->pUserData;
if(!iLoadable) {


Loading…
Cancel
Save