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.
This commit is contained in:
parent
796acc5539
commit
4f4371545b
1
ph7int.h
1
ph7int.h
|
@ -1277,6 +1277,7 @@ struct ph7_vm {
|
||||||
SySet aPaths; /* Set of import paths */
|
SySet aPaths; /* Set of import paths */
|
||||||
SySet aIncluded; /* Set of included files */
|
SySet aIncluded; /* Set of included files */
|
||||||
SySet aOB; /* Stackable output buffers */
|
SySet aOB; /* Stackable output buffers */
|
||||||
|
SySet aAutoLoad; /* Stack of class autoload callbacks */
|
||||||
SySet aShutdown; /* Stack of shutdown user callbacks */
|
SySet aShutdown; /* Stack of shutdown user callbacks */
|
||||||
SySet aException; /* Stack of loaded exception */
|
SySet aException; /* Stack of loaded exception */
|
||||||
SySet aIOstream; /* Installed IO stream container */
|
SySet aIOstream; /* Installed IO stream container */
|
||||||
|
|
77
vm.c
77
vm.c
|
@ -96,6 +96,15 @@ struct VmObEntry {
|
||||||
ph7_value sCallback; /* User defined callback */
|
ph7_value sCallback; /* User defined callback */
|
||||||
SyBlob sOB; /* Output buffer consumer */
|
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()] )
|
* Each installed shutdown callback (registered using [register_shutdown_function()] )
|
||||||
* is stored in an instance of the following structure.
|
* 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);
|
SyHashInit(&pVm->hDBAL, &pVm->sAllocator, 0, 0);
|
||||||
SySetInit(&pVm->aFreeObj, &pVm->sAllocator, sizeof(VmSlot));
|
SySetInit(&pVm->aFreeObj, &pVm->sAllocator, sizeof(VmSlot));
|
||||||
SySetInit(&pVm->aSelf, &pVm->sAllocator, sizeof(ph7_class *));
|
SySetInit(&pVm->aSelf, &pVm->sAllocator, sizeof(ph7_class *));
|
||||||
|
SySetInit(&pVm->aAutoLoad, &pVm->sAllocator, sizeof(VmAutoLoadCB));
|
||||||
SySetInit(&pVm->aShutdown, &pVm->sAllocator, sizeof(VmShutdownCB));
|
SySetInit(&pVm->aShutdown, &pVm->sAllocator, sizeof(VmShutdownCB));
|
||||||
SySetInit(&pVm->aException, &pVm->sAllocator, sizeof(ph7_exception *));
|
SySetInit(&pVm->aException, &pVm->sAllocator, sizeof(ph7_exception *));
|
||||||
/* Configuration containers */
|
/* 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);
|
ph7_result_value(pCtx, pArray);
|
||||||
return SXRET_OK;
|
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,...)
|
* void register_shutdown_function(callable $callback[,mixed $param,...)
|
||||||
* Register a function for execution on shutdown.
|
* Register a function for execution on shutdown.
|
||||||
|
@ -13453,6 +13496,7 @@ static const ph7_builtin_func aVmFunc[] = {
|
||||||
{ "function_exists", vm_builtin_func_exists },
|
{ "function_exists", vm_builtin_func_exists },
|
||||||
{ "is_callable", vm_builtin_is_callable },
|
{ "is_callable", vm_builtin_is_callable },
|
||||||
{ "get_defined_functions", vm_builtin_get_defined_func },
|
{ "get_defined_functions", vm_builtin_get_defined_func },
|
||||||
|
{ "register_autoload_handler", vm_builtin_register_autoload_handler },
|
||||||
{ "register_shutdown_function", vm_builtin_register_shutdown_function },
|
{ "register_shutdown_function", vm_builtin_register_shutdown_function },
|
||||||
{ "call_user_func", vm_builtin_call_user_func },
|
{ "call_user_func", vm_builtin_call_user_func },
|
||||||
{ "call_user_func_array", vm_builtin_call_user_func_array },
|
{ "call_user_func_array", vm_builtin_call_user_func_array },
|
||||||
|
@ -13628,9 +13672,36 @@ PH7_PRIVATE ph7_class *PH7_VmExtractClass(
|
||||||
/* Perform a hash lookup */
|
/* Perform a hash lookup */
|
||||||
pEntry = SyHashGet(&pVm->hClass, (const void *)zName, nByte);
|
pEntry = SyHashGet(&pVm->hClass, (const void *)zName, nByte);
|
||||||
if(pEntry == 0) {
|
if(pEntry == 0) {
|
||||||
/* No such entry,return NULL */
|
ph7_value *apArg[1];
|
||||||
iNest = 0; /* cc warning */
|
ph7_value sResult, sName;
|
||||||
return 0;
|
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;
|
pClass = (ph7_class *)pEntry->pUserData;
|
||||||
if(!iLoadable) {
|
if(!iLoadable) {
|
||||||
|
|
Loading…
Reference in New Issue