问题
I am writing an REST API and need to check weather the given model name exist or not in the directory.
1 - http://example.com/RestApi/index.php/api/posts/
2 - http://example.com/RestApi/index.php/api/post/
from these two, URL 1 is incorrect and URL 2 is correct (post). so i am taking this param and doing a search as following,
$model = $m::model()->findAll($criteria);
$m = TK::get('model');
when $m is incorrect, PHP warning include(posts.php): failed to open stream: No such file or directory will trigger.
so for that not to happen, i have written a function as modelExists() and using it like below.
If (!TK::modelExists($m))
$this->sendResponse(false, 1003);
the function body is as below,
/**
* Checks for a given model name
* @param string $modelName is the name of the model that is used to search against the directory.
* @return String $result, the name of Model. if doesnt exist NULL;
*/
public static function modelExists($modelName)
{
$result = null;
$basePath = Yii::getPathOfAlias('application').DIRECTORY_SEPARATOR;
$modelsDir = 'models'.DIRECTORY_SEPARATOR;
$modelName = strtolower($modelName).'.php';
$generalModelDir = scandir($basePath.$modelsDir);
foreach ($generalModelDir as $entry) { // Searching in General model directory
if ($modelName == strtolower($entry)) {
$temp = explode('.', $entry); // array('User','php')
$result = $temp[0];
break;
}
}
if (!$result) {
$modulePath = $basePath.'modules'.DIRECTORY_SEPARATOR;
$moduleDirectory = scandir($modulePath);
foreach ($moduleDirectory as $dir) {
$subModuleDirectory = scandir($modulePath.$dir);
foreach ($subModuleDirectory as $entry) {
if (is_dir($modulePath.$dir.DIRECTORY_SEPARATOR.$entry)) {
$directories = scandir($modulePath.$dir.DIRECTORY_SEPARATOR.$entry);
foreach ($directories as $subDir) {
if ($modelName == strtolower($subDir)) {
$temp = explode('.', $subDir); // array('User','php')
$result = $temp[0];
break;
}
}
}
}
}
}
return $result;
}
My Question is : Can this cause any performance issues since i am checking this for every API call ?
回答1:
Why not just have a map of all the classes in your project. That way you can use that instead of looking on the disk all the time.
Take a look at composer. Yes, I know it is a dependency manager but it is also an excellent autoload generator.
If you correctly add a composer.json with for example:
"autoload": {
"classmap": [
"protected/",
]
}
in it, it will auto generate a full class map array which you can load from vendor/composer/autoload_classmap.php. All you'd have to do is make sure the keys of the array are in lowercase and you can match 1 on 1. Just be sure to remember calling "composer dump-autoload" if you add new classes.
If you are doing it this way, consider just loading the complete autoloader instead (vendor/autoload.php) as it will assist Yii as a whole to limit disk searches. Have Yii profit even more from it by doing:
$loader = require(__DIR__ . '/../vendor/autoload.php');
Yii::$classMap = $loader->getClassMap();
In your index.php before you call the run() function. That way Yii can just look the class up in the array too.
For your problem, just call the $loader->getClassMap() function a second time and lowercase the array keys for your lookup table.
回答2:
As there are quite some filesystem related functions inside loops in your code, the performance penalty will be heavy due to all the issued syscalls. You should at least cache the result of your method.
An even better method might be this solution proposed by a Yii core dev :)
来源:https://stackoverflow.com/questions/20142553/model-exist-or-not-in-yii-using-a-custom-function-performance