I have an autoloader that is registered using spl_autoload_register():
class MyAutoLoader{
public function __construct(){
spl_autoload_register(array($this, 'loader'));
}
public function loader($className){
var_dump($className);
}
}
$al = new MyAutoLoader(); //Register the autoloader
From the var_dump(), the autoloader seems to be called on lots of things, things that are data to be inserted into a database, parameterized SQL queries and what not:
string 'name' (length=4)
string 'a:2:{s:5:"label";s:4:"Name";s:8:"required";b:1;}' (length=48)
string 'en_US' (length=5)
string 'object' (length=6)
string 'name = ?' (length=8)
These things will never be classes so should never be loaded using new or class_exists(), etc.
Under what circumstances/function calls are autoloaders called? I would like to put a stop to autoloading "classNames" that are not classes from being called, because each $className is checked using file_exist(), and having these data strings checked is pretty inefficient.
Problem resolved. I first did a back trace as suggested by Brad and dumped the traces to a file (just add a small snippet that opens a file and appends to it).
Obviously, the trace was very big, but I picked the simplest one I could find. Incidentally, that trace happened to be one that called a database (ORM) wrapper I have written to wrap around the awesome RedBean ORM library. The results from me dumping $className also validates that, because those strings are data are going into or coming out of the database.
Having said that, I have a __call() that intercepts methods to my database wrapper, does some processing, pass it to RedBean, process the result, and then sends it back to the caller.
Problem: During the processing, I am making calls to is_subclass_of() and instanceof, which will obviously ask the autoloader to try and load the class (since we don't have any class called name =? loaded, nor does it exist).
The solution was to actually make sure we have an object before calling is_subclass_of() and instanceof: if(is_object($someproperty) && is_subclass_of($someproperty)).
If $someproperty is not an object, the if immediately short-circuits and instanceof and is_subclass_of() is never called, which means the call to the autoloader is never made.
As mentioned by brad, having all sorts of things going to the autoloader to be included using require_once can be a huge security risk and at the same time, hitting the file system so many times using file_exists() is pretty inefficient too.
So, in conclusion, the autoloader is called every time you use instanceof, is_subclass_of, other class-type functions, class-exist functions and reflection methods, as Charles motioned in his answer.
So, the moral of the story is that if you plan to use a class-type function, or any of the functions mentioned above on a variable of mixed type, check it first before passing it to the class-type function.
Under what circumstances/function calls are autoloaders called?
I realize that this has ended up basically being a secondary question given the problems noted in the comments, but it's still worth answering.
Autoload functions, that being a __autoload() function in your code or callbacks registered through spl_autoload_register, are called when -- and only when -- PHP needs to access a class that has not been defined. This is done everywhere with few exceptions, such as class_exists, which have arguments that tell PHP not to call any autoloaders.
The PHP manual has a page dedicated to autoloading. I recommend reviewing it if there's any confusion.
You can use debug_backtrace or debug_print_backtrace to find out where exactly the auto-loader function is being called.
Technically it should only be called by PHP when a script references a class name that does not exist.
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.
A little background: At runtime I would like to be able to inspect the currently called functions javadoc-style documentation, to determine its formal (typed) declaration. This would allow runtime type checking (for simple and complex types) by means of reflection (at a cost) during debugging and testing, something that I would find immensely helpful.
So, in php I would like for a user defined function to get called whenever any other function is about to get called. That is, if a function foo() gets called, I would like to have my callHookHandler() function called immediately before.
One solution would be to implement __call() in all user defined classes, but that is both unwieldy and doesn't include support for functions defined outside classes, so I am looking for a better solution.
This sounds a bit of a fun one so I'm going to give answering it a try.
I hope this helps you. Let me know how it goes.
So, what you are asking can be done, and here's how:
For Functions:
Get all defined functions with $function = get_defined_functions().
Loop through the $functions['user'] key and inspect each one with the ReflectionFunction class. You'll need to get:
The comment using ->getDocComment()
The arguments using ->getParameters()
Do some magic (I'll let you figure out how to parse the comment using some regular extressions and match it up with the parameter list from the reflection. Don't forget optional parameters!)
Rename the function using runkit_function_rename
Generate code in a string that checks the parameters and calls the renamed function
Generate a parameter list as a string
Create a new function with runkit_function_add using the code you generated in step #5 and the parameter list from step #6.
For Classes:
Get a list of classes with $classes = get_declared_classes();
Loop through each one and inspect it with ReflectionObject and ->getMethods() to get the methods. Make sure that the class is not internal with ->isInternal() because we can't do anything about the internal classes.
In an inner loop... go through each method using the ReflectionMethod class. Get the arguments and PHPDoc/JavaDoc comments just like you did with normal functions.
Do the same thing you did with the functions only use runkit_method_add and runkit_method_rename instead.
Downsides:
You won't be able to do the checking on internal class methods and functions (which is fine because they won't have doc comments anyway).
This is a lot of work! I left a lot of parts up to your imagination to avoid this being the length of a short book.
Please send me this or open source it and let me know when you finish, I really want to use this myself. Contact info is on my website which is in my profile ;)
Alternatively:
You can use XDebug's function trace along with reflection then analyze the results after the fact so that you don't have to dynamically edit the code. If you want to write unit-test you could even automate it.
Hope type checking makes it into future versions of PHP and wait: https://wiki.php.net/rfc/typechecking
Notes:
This class reference has a potentially useful example of parsing docComments in the comments section of the page:
http://us.php.net/manual/en/class.reflectionmethod.php
References
get_defined_functions
get_declared_classes
ReflectionFunction
ReflectionObject
ReflectionMethod
runkit
Alternative way to hook into function call is to use a trick with namespaces: Intercepting Execution of System Functions in PHP
You can also use the Go! framework to define an aspect to intercept the execution of system functions automatically.
Reading up and picking up on unit testing, trying to make sense of the following post on that explains the hardships of static function calls.
I don't clearly understand this issue. I have always assumed static functions were a nice way of rounding up utility functions in a class. For example, I often use static functions calls to initialise, ie:
Init::loadConfig('settings.php');
Init::setErrorHandler(APP_MODE);
Init::loggingMode(APP_MODE);
// start loading app related objects ..
$app = new App();
// After reading the post, I now aim for this instead ...
$init = new Init();
$init->loadConfig('settings.php');
$init->loggingMode(APP_MODE);
// etc ...
But, the few dozen tests I had written for this class are the same. I changed nothing and they still all pass. Am I doing something wrong?
The author of the post states the following:
The basic issue with static methods is they are procedural code. I have no idea how to unit-test procedural code. Unit-testing assumes that I can instantiate a piece of my application in isolation. During the instantiation I wire the dependencies with mocks/friendlies which replace the real dependencies. With procedural programing there is nothing to “wire” since there are no objects, the code and data are separate.
Now, I understand from the post that static methods create dependencies, but don't grasp intuitively why one cannot test the return value of a static method just as easily as a regular method?
I will be avoiding static methods, but I would of liked having an idea of WHEN static methods are useful, if at all. It seems from this post static methods are just about as evil as global variables and should be avoided as much as possible.
Any additional information or links on the subject would be greatly appreciated.
Static methods themselves aren't harder to test than instance methods. The trouble arises when a method--static or otherwise--calls other static methods because you cannot isolate the method being tested. Here is a typical example method that can be difficult to test:
public function findUser($id) {
Assert::validIdentifier($id);
Log::debug("Looking for user $id"); // writes to a file
Database::connect(); // needs user, password, database info and a database
return Database::query(...); // needs a user table with data
}
What might you want to test with this method?
Passing anything other than a positive integer throws InvalidIdentifierException.
Database::query() receives the correct identifier.
A matching User is returned when found, null when not.
These requirements are simple, but you must also setup logging, connect to a database, load it with data, etc. The Database class should be solely responsible for testing that it can connect and query. The Log class should do the same for logging. findUser() should not have to deal with any of this, but it must because it depends on them.
If instead the method above made calls to instance methods on Database and Log instances, the test could pass in mock objects with scripted return values specific to the test at hand.
function testFindUserReturnsNullWhenNotFound() {
$log = $this->getMock('Log'); // ignore all logging calls
$database = $this->getMock('Database', array('connect', 'query');
$database->expects($this->once())->method('connect');
$database->expects($this->once())->method('query')
->with('<query string>', 5)
->will($this->returnValue(null));
$dao = new UserDao($log, $database);
self::assertNull($dao->findUser(5));
}
The above test will fail if findUser() neglects to call connect(), passes the wrong value for $id (5 above), or returns anything other than null. The beauty is that no database is involved, making the test quick and robust, meaning it won't fail for reasons unrelated to the test like network failure or bad sample data. It allows you to focus on what really matters: the functionality contained within findUser().
Sebastian Bergmann agrees with Misko Hevery and quotes him frequently:
Stubbing and Mocking Static Methods
Unit-Testing needs seams, seams is where we prevent the execution of normal code path and is how we achieve isolation of the class under test. Seams work through polymorphism, we override/implement class/interface and then wire the class under test differently in order to take control of the execution flow. With static methods there is nothing to override. Yes, static methods are easy to call, but if the static method calls another static method there is no way to override the called method dependency.
The main issue with static methods is that they introduce coupling, usually by hardcoding the dependency into your consuming code, making it difficult to replace them with stubs or mocks in your Unit-Tests. This violates the Open/Closed Principle and the Dependency Inversion Principle, two of the SOLID principles.
You are absolutely right that statics are considered harmful. Avoid them.
Check the links for additional information please.
Update: note that while statics are still considered harmful, the capability to stub and mock static methods has been removed as of PHPUnit 4.0
I do not see any problem when testing static methods (at least none that doesn't exists in non-static methods).
Mock objects are passed to classes under test using dependency injection.
Mock static methods can be passed to classes under test using a suitable autoloader or manipulating the include_path.
Late static binding deals with methods calling static methods in the same class.
A word before my question to say I am pretty new to OOP in PHP, and I'm very grateful to the site, and you all for reading - and sometimes answering beautifully (as you can see here or here, or even here) and helping big time my late (sort of) improvement dealing with classes.
All my previous questions lead me today to this one:
In a class extending PDOStatement, how can I trigger a default action each time one of the parent public methods is called?
I can do this:
class genc_query extends PDOStatement{
public function rowCount(){
$this->myDefaultAction();
return parent::rowCount();
}
}
But as I need to change in the same way almost all of the native methods, I wonder if there's no way to trigger a function like __call() as if these methods were private (as it's not possible to make them private).
as it's not possible to make them private
Indeed, this seems to be the case.
ReflectionMethod can let you change the accessibility of a method, but it seems that it either doesn't work on internal methods (i.e. not user-defined) or it won't set public methods to protected/private. It seems designed to make protected/private methods public instead.
It looks like your copy-and-paste boilerplate inside each method is going to be necessary. Besides __sleep and __wakeup, there are only about three dozen methods, so it should only take you a few minutes.
For the sake of clear code, extend every method (means: overwrite and call parent::method() there), that you wants to have additional behaviour. Else there will be some day, where you or someone else may get really confused on what happens there.
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.