Quindi ho avuto questa idea di mappare la struttura delle cartelle del framework in spazi dei nomi con un processo di compilazione dinamico.
Per darti un'idea di come funzionerebbe qui una struttura di esempio:
src/
FS/
File/
open.php (function)
Math/
add.php (function)
test.php (function)
MAGIC.php (constant)
Sarebbe tradotto in:
namespace FS\File {
function open() { /* ... */ }
}
namespace Math {
function add() { /* ... */ }
function test() { /* ... */ }
const MAGIC = /* ... */;
}
Non ci sarebbe alcun supporto per le classi.
Una funzione sarebbe definita come segue:
<?php
/**
* src/Math/add.php
*
* This is the Math\add module.
*/
return function($require) {
// Require Math\test module.
$test = $require('Math\test');
return function($a, $b) use ($test) {
// Call Math\test function
$test($a, $b);
return $a + $b;
};
};
?>
La funzione più esterna serve per fornire un nuovo ambito (quindi tutte le variabili definite precedentemente non sono esistenti).
Quindi la variabile $require
serve per includere altri moduli.
(L'idea di richiedere tutte le altre dipendenze proveniva da node
. Penso che ciò renderebbe il mocking e il testing molto più semplice perché si potrebbe testare il modulo con una variabile $require
sovrascritta.)
E le costanti possono essere definite come segue:
<?php
/**
* src/Math/MAGIC.php
*/
return 0xDEADBEEF;
?>
L'intero framework avrebbe quindi un metodo require
per caricare un modulo dal filesystem:
/**
* Function that is responsible to load a module.
*/
function require($module) {
static $loadedModules = [];
$modFileName = str_replace('\', '/', $module);
// Check if already loaded or load from file system
// ...
// ...
return $loadedModule;
}
Quindi usare Math \ add sarebbe simile a questo:
require('Math\add')('require')(1, 2)
// ^- dependency loader function
Ovviamente questo non sembra molto carino, quindi il processo di generazione genererebbe gli spazi dei nomi e completerà automaticamente le chiamate richieste:
namespace Math {
function add(...$args) {
return require(__FUNCTION__)('require')(...$args);
}
/* Or constants ... */
const MAGIC = 0xDEADBEEF;
}
Le costanti potrebbero essere richieste nello stesso modo delle funzioni:
require('Math\MAGIC') // 0xDEADBEEF
// or through the generated namespace
Math\MAGIC // 0xDEADBEEF
I vantaggi che vedo:
- Struttura flessibile (gli spazi dei nomi sono generati automaticamente).
- Facilmente mockable e testabile.
- Cancella dipendenze (le dipendenze sono sempre
require
'd)
Ma posso anche vedere il pericolo di avere troppe variabili a causa del modo in cui vengono gestite le dipendenze. Inoltre non sono troppo sicuro delle prestazioni.
Non ho mai visto un'architettura del genere e sono curioso di sapere cosa pensano gli altri del mio concetto.