We have a standard in use, where we create exceptions within the main class for returning errors etc... The problem is, that all the standard sniffs do not like this. We are writing our own sniffs then for this, but thought I would inquire why this was not desirable?
For instance, we have:
<?php
class FOO_EXCEPTION extends Exception { }
class FOO_EXCEPTION_BAR extends FOO_EXCEPTION { }
class FOO_EXCEPTION_POLE extends FOO_EXCEPTION { }
class FOO
{
public function MethodDoingSomething()
{
if('some condition happens') {
throw new FOO_EXCEPTION_BAR();
}
if('some other condition') {
throw new FOO_EXCEPTION_POLE();
}
...
}
}
?>
This allows our code to return different exceptions to indicate what happened to the caller, but if a dedicated try/catch is not available, the basic Exception may still be caught.
This comes in handy when working with databases or other external objects, since the nature of the error may be returned to a component higher up the call stack to handle the error.
For instance, if you are deleting a file, and the file does not exist, the code may throw the exception, but the caller has the option to ignore this if it was not concerned that the file did not exist, since it was trying to delete it anyhow. However, another caller, could error out with the absence of a file that was suppose to exist when it was being deleted.
In my opinion, the coding standard which you describe in your question is perfectly reasonable. And I think for the purposes of your project it would be better to tweak the "standard multiple classes per file" sniff so that it works with your code in this particular (special) case rather than waste your time tweaking your codebase to comply with "the letter of the law" for this particular sniff.
I agree with the assertion that it is better in general to avoid putting multiple class definitions in a single file. But every argument I've read (so far) for moving each and every Exception-derived class into its own separate file strikes me as an exhortation to "improve" code by making it less readable. As a human, I gain no maintainability benefit from cluttering my code with files containing a single line, each.
It's true that it is easier to write an autoloader, for example, if each class lives in its own file. And if you're generating/compiling your PHP code from some sort of meta-language then it costs you nothing to add extra levels to your directory structure. But I reject the conclusion that this way of organizing the code actually improves it in any useful-to-humans way.
EDIT:
For the record, I can see that it would be a good idea to move the definition of an Exception-derived class into its own file if it actually contains some "testable" logic. In such cases you might need to mock/stub the class when writing automated tests for the logic which uses the class, which would require you to be able to load the class definition separately from the logic which uses it. But this not the situation described in the original question, where the Exception-derived classes are all "empty".
Related
I am quite new to OOP, so this is really a basic OOP question, in the context of a Laravel Controller.
I'm attempting to create a notification system system that creates Notification objects when certain other objects are created, edited, deleted, etc. So, for example, if a User is edited, then I want to generate a Notification regarding this edit. Following this example, I've created UserObserver that calls NotificationController::store() when a User is saved.
class UserObserver extends BaseObserver
{
public function saved($user)
{
$data = [
// omitted from example
];
NotificationController::store($data);
}
}
In order to make this work, I had to make NotificationController::store() static.
class NotificationController extends \BaseController {
public static function store($data)
{
// validation omitted from example
$notification = Notification::create($data);
}
I'm only vaguely familiar with what static means, so there's more than likely something inherently wrong with what I'm doing here, but this seems to get the job done, more or less. However, everything that I've read indicates that static functions are generally bad practice. Is what I'm doing here "wrong," per say? How could I do this better?
I will have several other Observer classes that will need to call this same NotificationController::store(), and I want NotificationController::store() to handle any validation of $data.
I am just starting to learn about unit testing. Would what I've done here make anything difficult with regard to testing?
I've written about statics extensively here: How Not To Kill Your Testability Using Statics. The gist of it as applies to your case is as follows:
Static function calls couple code. It is not possible to substitute static function calls with anything else or to skip those calls, for whatever reason. NotificationController::store() is essentially in the same class of things as substr(). Now, you probably wouldn't want to substitute a call to substr by anything else; but there are a ton of reasons why you may want to substitute NotificationController, now or later.
Unit testing is just one very obvious use case where substitution is very desirable. If you want to test the UserObserver::saved function just by itself, because it contains a complex algorithm which you need to test with all possible inputs to ensure it's working correctly, you cannot decouple that algorithm from the call to NotificationController::store(). And that function in turn probably calls some Model::save() method, which in turn wants to talk to a database. You'd need to set up this whole environment which all this other unrelated code requires (and which may or may not contain bugs of its own), that it essentially is impossible to simply test this one function by itself.
If your code looked more like this:
class UserObserver extends BaseObserver
{
public function saved($user)
{
$data = [
// omitted from example
];
$this->NotificationController->store($data);
}
}
Well, $this->NotificationController is obviously a variable which can be substituted at some point. Most typically this object would be injected at the time you instantiate the class:
new UserObserver($notificationController)
You could simply inject a mock object which allows any methods to be called, but which simply does nothing. Then you could test UserObserver::saved() in isolation and ensure it's actually bug free.
In general, using dependency injected code makes your application more flexible and allows you to take it apart. This is necessary for unit testing, but will also come in handy later in scenarios you can't even imagine right now, but will be stumped by half a year from now as you need to restructure and refactor your application for some new feature you want to implement.
Caveat: I have never written a single line of Laravel code, but as I understand it, it does support some form of dependency injection. If that's actually really the case, you should definitely use that capability. Otherwise be very aware of what parts of your code you're coupling to what other parts and how this will impact your ability to take it apart and refactor later.
GOAL:
I'm interested in generating a DOT Format description of the class dependencies in a PHP program.
IDEA:
It shouldn't be hard to write a CodeSniffer "sniff" that can detect (and emit DOT records for) the following patterns in PHP source:
class SomeClassName extends BasicClassName { // SomeClassName refers to BasicClassName
...
new OtherClassName(); // SomeClassName refers to OtherClassName
ThisClassName::some_method(); // SomeClassName refers to ThisClassName
ThatClassName::$some_member; // SomeClassName refers to ThatClassName
RandomClassName::some_constant; // SomeClassName refers to RandomClassName
...
}
But I haven't found any published sniffs to emit this information (and any other patterns indicating a "real" class dependency relationship that I may have missed).
NOTE:
I specifically do not care about PHP's include() and require() statements (whose behavior I'm not convinced is even well-defined). For the purposes of this question let's assume that all PHP class resolution is handled via autoloading, and that we're looking to use only static code analysis to build the class dependency diagram.
EDIT:
Unfortunately, I see no general way to deal with the following:
class ThatClassName {
...
function generateClassName() {
// something too complicated to analyze statically...
}
function foo() {
$name = $this->generateClassName();
$instance = new $name; // ThatClassName refers to ... what?
...
}
...
}
But of course it would be possible to represent this scenario in a dependency graph by showing ThatClassName with a dependency on the generateClassName() method - perhaps shown with parens to make the method name easily distinguishable from a class name. And it probably wouldn't be a bad idea to establish a convention whereby any method which generates a class name dynamically must contain an annotation (in the associated comment) which indicates every class name which might possibly be generated - these "documented dynamic dependencies" could then be automatically included in the dependency graph.
This isn't really what PHP_CodeSniffer is designed to do; specifically because the sniffs are not supposed to output data or write to files. But, there is certainly nothing stopping you from doing this inside a sniff. It's just PHP code after all and it doesn't need to report any errors or warnings.
I haven't come across any sniffs that are doing anything like you describe, so I think you'd have to write a new one.
If you want to create a new sniff, I'd recommend starting with an abstract scope sniff. This allows you to look for T_NEW and T_DOUBLE_COLON tokens inside T_CLASS tokens. Here is an example.
Or, if you also want to look into global functions and other code outside classes, you can just look for T_NEW and T_DOUBLE_COLON tokens inside a regular sniff
If you're not sure how to get started or you just want some help writing the sniff, contact me and I can help write this with you. I'd just need to know what output you'd want for each case found, or I can just use something basic. If you want a hand, my email is: gsherwood at squiz dot net
I wrote a tool for this: PhpDependencyAnalysis.
This is an extandable static code analysis for object-oriented PHP-Projects (>= 5.3.3) based on namespaces. It creates dependency graphs on customizable levels, e.g. on package-level or on class-level. Thus, it's usable to declare dependencies in general, but it's also usable to perform a detection of violations between layers in a tiered architecture according to compliance with Separation of Concerns, Law of Demeter and Acyclic Dependencies Principle.
You can also change the output format to DOT.
Just check PhpDependencyAnalysis on GitHub.
I have asked a similar question to this one already but I think it was badly worded and confusing so hopefully I can make it a bit clearer.
I am programming in a native Linux file system.
I have a class of HelpTopic:
class HelpTopic extends Help{}
And a class of Help:
class Help{}
Now I go to include HelpTopic:
include('HelpTopic.php');
And even though I do not instantiate HelpTopic with new HelpTopic() PHP (in a Linux file system) still reads the class signature and tries to load Help with HelpTopic.
I do not get this behaviour from a cifs file system shared from a Windows System.
My best guess is that there is some oddity with Linux that causes PHP to react this way but not sure what.
Does anyone have any ideas or solutions to this problem?
EDIT:
I have added my loading function to show what I am doing:
public static function import($cName, $cPath = null){
if(substr($cName, -2) == "/*"){
$d_name = ROOT.'/'.substr($cName, 0, -2);
$d_files = getDirectoryFileList($d_name, array("\.php")); // Currently only accepts .php
foreach($d_files as $file){
glue::import(substr($file, 0, strrpos($file, '.')), substr($cName, 0, -2).'/'.$file);
}
}else{
if(!$cPath) $cPath = self::$_classMapper[$cName];
if(!isset(self::$_classLoaded[$cName])){
self::$_classLoaded[$cName] = true;
if($cPath[0] == "/" || preg_match("/^application/i", $cPath) > 0 || preg_match("/^glue/i", $cPath) > 0){
return include ROOT.'/'.$cPath;
}else{
return include $cPath;
}
}
return true;
}
}
I call this by doing glue::inmport('application/models/*'); and it goes through including all the models in my app. Thing is PHP on a linux based file system (not on cifs) is trying to load the parents of my classes without instantiation.
This is a pretty base function that exists in most frameworks (in fact most of this code is based off of yiis version) so I am confused why others have not run into this problem.
And even though I do not instantiate HelpTopic with new HelpTopic() PHP still reads the class signature and tries to load Help with HelpTopic.
Correct.
In order to know how to properly define a class, PHP needs to resolve any parent classes (all the way up) and any interfaces. This is done when the class is defined, not when the class is used.
You should probably review the PHP documentation on inheritance, which includes a note explaining this behavior:
Unless autoloading is used, then classes must be defined before they are used. If a class extends another, then the parent class must be declared before the child class structure. This rule applies to class that inherit other classes and interfaces.
There are two ways to resolve this problem.
First, add a require_once at the top of the file that defines the child class that includes the file defining the parent class. This is the most simple and straight-forward way, unless you have an autoloader.
The second way is to defione an autoloader. This is also covered in the documentation.
The ... thing ... you're using there is not an autoloader. In fact, it's a horrible abomination that you should purge from your codebase. It's a performance sap and you should not be using it. It also happens to be the thing at fault.
We don't have the definition of getDirectoryFileList() here, so I'll assume it uses either glob() or a DirectoryIterator. This is the source of your problem. You're getting the file list in an undefined order. Or, rather, in whatever order the underlying filesystem wants to give to you. On one machine, the filesystem is probably giving you Help.php before HelpTopic.php, while on the other machine, HelpTopic.php is seen first.
At first glance, you might think this is fixable with a simple sort, but it's not. What happens if you create a Zebra class, and then later need to create an AlbinoZebra that inherits from it? No amount of directory sorting is going to satisfy both the "load ASCIIbetical" and the "I need the Zebra to be first" requirements.
Let's also touch on the performance aspect of the problem. On every single request, you're opening a directory and reading the list of files. That's one hell of a lot of stat calls. This is slow. Very slow. Then, one by one, regardless of whether or not you'll need them, you're including the files. This means that PHP has to compile and interpret every single one of them. If you aren't using a bytecode cache, this is going to utterly destroy performance if the number of files there ever grows to a non-trivial number.
A properly constructed autoloader will entirely mitigate this problem. Autoloaders run on demand, meaning that they'll never attempt to include a file before it's actually needed. Good-performing autoloaders will know where the class file lives based on the name alone. In modern PHP, it's accepted practice to name your classes such that they'll be found easily by an autoloader, using either namespaces or underscores -- or both -- to map directory separators. (Meaning namespace \Models; class Help or class Models_Help would live in Models/Help.php)
Unfortunately most examples won't be useful here, as I don't know what kind of weird things your custom framework does. Take a peek at the Zend Framework autoloader, which uses prefix registration to point class prefixes (Model_) at directories.
PHP's __autoload() (documentation) is pretty interesting to me. Here's how it works:
You try to use a class, like new Toast_Mitten()(footnote1)
The class hasn't been loaded into memory. PHP pulls back its fist to sock you with an error.
It pauses. "Wait," it says. "There's an __autoload() function defined." It runs it.
In that function, you have somehow mapped the string Toast_Mitten to classes/toast_mitten.php and told it to require that file. It does.
Now the class is in memory and your program keeps running.
Memory benefit: you only load the classes you need. Terseness benefit: you can stop including so many files everywhere and just include your autoloader.
Things get particularly interesting if
1) Your __autoload() has an automatic way of determining the file path and name from the class name. For instance, maybe all your classes are in classes/ and Toast_Mitten will be in classes/toast_mitten.php. Or maybe you name classes like Animal_Mammal_Weasel, which will be in classes/animal/mammal/animal_mammal_weasel.php.
2) You use a factory method to get instances of your class.
$Mitten = Mitten::factory('toast');
The Mitten::factory method can say to itself, "let's see, do I have a subclass called Toast_Mitten()? If so, I'll return that; if not, I'll just return a generic instance of myself - a standard mitten. Oh, look! __autoload() tells me there is a special class for toast. OK, here's an instance!"
Therefore, you can start out using a generic mitten throughout your code, and when the day comes that you need special behavior for toast, you just create that class and bam! - your code is using it.
My question is twofold:
(Fact) Do other languages have similar constructs? I see that Ruby has an autoload, but it seems that you have to specify in a given script which classes you expect to use it on.
(Opinion) Is this too magical? If your favorite language doesn't do this, do you think, "hey nifty, we should have that" or "man I'm glad Language X isn't that sloppy?"
1 My apologies to non-native English speakers. This is a small joke. There is no such thing as a "toast mitten," as far as I know. If there were, it would be a mitten for picking up hot toast. Perhaps you have toast mittens in your own country?
Both Ruby and PHP get it from AUTOLOAD in Perl.
http://perldoc.perl.org/perltoot.html#AUTOLOAD:-Proxy-Methods
http://perldoc.perl.org/AutoLoader.html
Note that the AutoLoader module is a set of helpers for common tasks using the AUTOLOAD functionality.
Do not use __autoload(). It's a global thing so, by definition, it's somewhat evil. Instead, use spl_autoload_register() to register yet another autoloader to your system. This allows you to use several autoloaders, what is pretty common practice.
Respect existing conventions. Every part of namespaced class name is a directory, so new MyProject\IO\FileReader(); should be in MyProject/IO/FileReader.php file.
Magic is evil!
The Mitten::factory method can say to itself, "let's see, do I have a subclass called Toast_Mitten()? If so, I'll return that; if not, I'll just return a generic instance of myself - a standard mitten. Oh, look! __autoload() tells me there is a special class for toast. OK, here's an instance!"
Rather such tricky code, use simple and verbose one:
try {
$mitten = new ToastMitten();
// or $mitten = Mitten::factory('toast');
} catch (ClassNotFoundException $cnfe) {
$mitten = new BaseMitten();
}
I think this feature comes in very handy, and I have not seen any features like it else where. Nor have I needed these features else where.
Java has something similar. It's called a ClassLoader. Probably other languages too, but they stick with some default implementation.
And, while we're at this. It would have been nice if __autoload loaded any type of symbols, not just classes: constants, functions and classes.
See Ruby's Module#const_missing
I just learned this: Ruby has a method on Module called const_missing that gets called if you call Foo::Bar and Bar isn't in memory yet (although I suppose that Foo has to be in memory).
This example in ruby-doc.org shows a way to use that to implement an autoloader for that module. This is in fact what Rails uses to load new ActiveRecord model classes, according to "Eloquent Ruby" by Russ Olsen (Chapter 21, "Use method_missing for flexible error handling", which also covers const_missing).
It's able to do this because of the "convention over configuration" mindset: if you reference a model called ToastMitten, if it exists, it will be in app/models/toast_mitten.rb. If you could put that model any place you wanted, Rails wouldn't know where to look for it. Even if you're not using Rails, this example, and point #1 in my question, shows how useful it can be to follow conventions, even if you create them yourself.
In my project, say I am instantiating a class named SubClass, which extends an abstract class named AbstractClass. At the top of my files I include a file named bootstrap.inc, which includes AbstractClass in every file. Then, when I need it, I include SubClass which does not contain an include to AbstractClass.
If I include AbstractClass in the files of classes that extend it (such as SubClass), sometimes I am using multiple sub-classes in one file and will get an error. I would rather not include AbstractClass in every file via the bootstrap, since I am not always using it, but cannot think of a way to avoid this.
I have been advised that using include_once() is a sign of poor design, so have avoided that, although it would be one solution.
Is there an alternative method to include_once()?
First off - it's generally a good idea to stick to one class per file. If you're worried about performance, you're being paranoid. In production, you can always turn on APC with stat off.
Secondly - there's nothing wrong with include_once/require_once.
Unless you're going to set up some fancy autoloading magic, just stick to one class per file.
Absent some specific concern (that is, something articulable that you actually understand, not just some rumor you heard), the following pattern is perfectly fine:
<?PHP
require_once 'MyAbstract.class.php';
class Concrete extends MyAbstract {
//...
}
// end-of-file
PHP's Autoloading mechanism could be ideal for you.
That said, there's nothing wrong with include_once(). What that person talking about a design flaw was probably referring to is that a code flow that includes the same file more than once (thus making include_once() necessary over include() is most likely badly designed.