Reputation: 971
I've been planning to write a small PHP framework with a group of developers for internal use and there's an issue that one of the developers has with several existing frameworks that we're trying to resolve in ours.
In some frameworks, the class name (of a controller or model) must match the file name. The developer thinks that this is an extra development overhead and we've been coming up with ways to resolve this issue.
On the other hand, if we have no rules for file names and the class names they contain, then people could include files like a.php
which contains the UserController
class and other developers will have to open each file to figure out what class is contained in what file.
What this particular developer suggested is that we make files with semantic file names, (say cart.php
and this will contain code without the class wrapper.
For example (taken from PHP.net), instead of
<?php
class Cart {
var $items; // Items in our shopping cart
// Add $num articles of $artnr to the cart
function add_item($artnr, $num) {
$this->items[$artnr] += $num;
}
// Take $num articles of $artnr out of the cart
function remove_item($artnr, $num) {
if ($this->items[$artnr] > $num) {
$this->items[$artnr] -= $num;
return true;
} elseif ($this->items[$artnr] == $num) {
unset($this->items[$artnr]);
return true;
} else {
return false;
}
}
}
?>
we write
var $items; // Items in our shopping cart
// Add $num articles of $artnr to the cart
function add_item($artnr, $num) {
$this->items[$artnr] += $num;
}
// Take $num articles of $artnr out of the cart
function remove_item($artnr, $num) {
if ($this->items[$artnr] > $num) {
$this->items[$artnr] -= $num;
return true;
} elseif ($this->items[$artnr] == $num) {
unset($this->items[$artnr]);
return true;
} else {
return false;
}
}
and then we read that file, say using file_get_contents
, prepend and append the required code to make it a proper class (with the same name as the filename), and then eval
it instead of just including the complete file (including the class).
What problems could arise from doing this, apart from:
UPDATE
Please refrain from giving the above two reasons in various forms. We're aware that the approach is unsemantic and slow.
Also, we would also like to hear about a direct include()
vs eval()
argument. Apart from the above two reasons as well as reasons of ease of use and easier project/system management, why should one use include()
over eval()?
Upvotes: 2
Views: 810
Reputation: 97783
The "problem" you are trying to solve is generally considered a good thing: if the code has to live in a file somewhere, then you need a naming convention for such files in order to organise the project; and since you also need a naming convention for namespaces and classes, aligning the two actually saves effort, because you don't need to keep track of both conventions.
PHP also includes a feature which gives an even stronger advantage to this, in the form of autoloading. This allows you to write a function which, whenever you mention a class that hasn't been defined yet, will be called with that class name; by aligning your filenames to class names, it can then find and load that class. This is tremendously useful as your project grows, because it means you never need to add require
or include
to files, or work out the exact tree of dependencies required for a particular area of your code. The major frameworks have collaborated on a standardised directory layout to take advantage of this, called PSR-4.
While it can be annoying having to create large numbers of directories and separate files, and tempting to put many small classes into one file, this doesn't scale well, and if one of those small classes later grows, you'll regret it not having its own file, with its own version history, etc.
If you don't name your files after the class they contain, you will need to either manually manage a complex set of require
/include
lines tracking the right order to define everything in, or have an autoloader function with a long list mapping class names to filenames. Either sounds like a lot of work for no gain to me.
If your files are going to be named after the class anyway, then an autoloader would still work, but the only thing you are gaining is that you don't need to type the words class Cart
at the top of the file. On the other hand, you will need to create a rather unusual function for including these files, involving a rather inefficient use of eval()
. Things like OpCache and HHVM will find it much harder to cache and optimise code loaded this way, and any tool performing static analysis will be completely defeated as the code in the file will not be valid (e.g. PHPCodeSniffer for reporting on coding standards, PHPDocumentor, or any editor or IDE providing function lists and syntax parsing features).
Finally, it is often remarked that code is read much more often than it is written. The step you are saving happens, for the vast majority of classes, exactly once - when the class is first created. Renaming or copying a class is generally a very rare occurrence, and if you're renaming a large number of files, it's fairly easy to make a script to automate the task. On the other hand, you are introducing several things which make reading your code harder. As well as confounding static analysis (and thus automated documentation), you will have to explain this idiosyncratic scheme to new developers working on the project, so effectively increase your training costs. There is also the problem that, once this scales beyond a single directory, you will have to look at the full directory path of a file to see what class it actually defines; I frequently end up with several files open with the same name (e.g. search_handler.php
) and the fact that I (and my editor) can look at the top of the file for the full class declaration is essential for keeping track of which is which.
Upvotes: 4