Auteur: Richard - 05 april 2009 - 15:32 - Gekeurd door: Koen - Hits: 2693 - Aantal punten: 4.75 (2 stemmen)
Crosspost met PHPFreakz.nl
Aangezien ik een redelijke vreemde structuur voor m'n klassen heb qua bestanden heb ik niet genoeg aan een standaard autoloader.
Ik had dus een scanner nodig die m'n include path doorloopt om een map te maken van klassenaam => bestand, en hier is het resultaat.
Het is gebaseerd op de tokenizer (wanneer niet), aangezien die beter kan bepalen dan ik waar een klassenaam staat, en het is ook nog eens verrekkes snel. :-)
Opmerkingen, commentaar, enzovoorts mag je achterlaten als reactie.
<?php
/**
* Klassenaamscanner inclusief voorbeeld
*
* @author Richard van Velzen
*/
/**
* Scanner voor klasse- en interfacenamen in een bestand
*
* @param string $inputFile Bestand waarin namen gevonden moeten worden
* @return array Array van klasse- en interfacenamen
* @author Richard van Velzen
*/
function classNameScanner($inputFile) {
if(!is_readable($inputFile)) {
throw new InvalidArgumentException('Inputbestand is niet leesbaar');
}
$foundNames = array();
// haal alle tokens uit het bestand op
$tokens = token_get_all(file_get_contents($inputFile));
for($i = 0, $length = count($tokens); $i !== $length; ++$i) {
if(is_array($tokens[$i]) && ($tokens[$i][0] === T_CLASS || $tokens[$i][0] === T_INTERFACE)) {
// begin te zoeken naar een T_STRING, en skip whitespace en comments
for($j = $i + 1; $j !== $length; ++$j) {
if(is_array($tokens[$j])) {
if($tokens[$j][0] == T_STRING) {
// we hebben een naam gevonden, gooi maar in de array
$foundNames[] = $tokens[$j][1];
continue 2;
} elseif($tokens[$j][0] == T_WHITESPACE || $tokens[$j][0] == T_COMMENT || $tokens[$j][0] == T_DOC_COMMENT) {
// whitespace en comments skippen we
continue;
}
}
// hier klopt iets niet, hier hadden we nooit moeten komen
// gooi een exception aangezien de syntax niet klopt en dit
// bestand dus nooit geinclude kan worden
throw new RuntimeException('Syntaxfout: geen naam gevonden na "class" of "interface"');
}
}
}
return $foundNames;
}
// stel je eigen includepath hier in
set_include_path('framework' . PATH_SEPARATOR . get_include_path());
$classMap = array();
// we willen het hele includepath maar al te graag gebruiken :-)
foreach(explode(PATH_SEPARATOR, get_include_path()) as $includePath) {
// OS specifieke directory separator gebruiken
$includePath = str_replace('\/', DIRECTORY_SEPARATOR, $includePath);
if(substr($includePath, - 1, 1) !== DIRECTORY_SEPARATOR) {
$includePath .= DIRECTORY_SEPARATOR;
}
// haal alle PHP en INC files op
$files = glob($includePath . '*.{php,inc}', GLOB_BRACE);
foreach($files as $file) {
$file = realpath($file);
foreach(classNameScanner($file) as $className) {
$className = strtolower($className);
if(!isset($classMap[$className])) {
// alleen de eerste nemen, de rest zou nooit geinclude worden
$classMap[$className] = $file;
}
}
}
}
print_r($classMap);
?>
<?php
/**
* Klassenaamscanner inclusief voorbeeld
*
* @author Richard van Velzen
*/
/**
* Scanner voor klasse- en interfacenamen in een bestand
*
* @param string $inputFile Bestand waarin namen gevonden moeten worden
* @return array Array van klasse- en interfacenamen