There are these situations where you do need to figure out what and how many objects were created when you run your PHP scripts. There are a lot of reasons to do this:
Fatal error: Allowed memory size of N bytes exhausted
,You can use sophisticated tools such as php-meminfo and get really granular and deep into what is going on. Or ... you can do something quick and dirty although not very accurate, but yet a good guess.
That thing is to take a profiling output and count the number of constructors called.
You can do that with a local xdebug
cachegrind output, or you can use a
Blackfire profile too - they are more or less the same
thing. Here is an example from a public Blackfire profile I found on the web:
https://blackfire.io/profiles/355d29d5-5e6d-4977-bdb9-e49d9c7c5bdd/graph
Now go there and search for __construct()
and you get 36 constructors, which
most likely means 36 instantiated objects.
You can do the same with your favorite cachegrind reader (qcachegrind,
kcachegrind,
wincachegrind or whatever): just search
to find how many times __construct()
methods have been called.
As I said at the beginning, this is not accurate.
First, there are classes that do not have constructors, like stdClass
for
example. You will not be able to count those types of objects this way
Second, speaking of stdClass
- all of the objects returned from json_decode()
will also not have constructors.
Finally, unserialize()
: when you unserialize objects their constructors are
not called. If the classes of the serialized objects implement the Serializable
interface, then the Serializable::unserialize()
method acts as the constructor:
Note:
This method acts as the constructor of the object. The __construct() method will not be called after this method.
You can also look for __wakeup()
and __unserialize()
as those are also used
when unserializing objects.
Perhaps there might be one or more few other places where new objects are created without calling their constructors, but so far these three are the only ones I know of at the moment.
With that being said, I hope this will be of a tiny bit of help for you as it is for me.
Few days ago I wrote this, and at the time I felt I was missing something, but I could not figure out what it was, so arrogant me published this post anyway:
Perhaps there might be one or more few other places where new objects are created without calling their constructors, but so far these three are the only ones I know of at the moment.
As it usually happens, I did missed a very obvious one. I got reminded of this
when I was inspecting another Blackfire profile for a Laravel demo, and yet
it only had few constructors for Symfony classes and ReflectionClass
. Surely
there should be some Laravel objects created under the Illuminate\
namespace,
but I didn't see any. That's when I realized what I was missing from that list:
ReflectionClass::newInstanceArgs()
.
public ReflectionClass::newInstanceArgs ( array $args = [] ) : object
Creates a new instance of the class, the given arguments are passed to the class constructor.
https://www.php.net/manual/en/reflectionclass.newinstanceargs.php
It's very obvious, isn't it? Nowadays almost nobody is creating new objects directly
and everyone is using one form of another of IoC container. To resolve all the
dependencies injected via the constructors, the containers must be able to create
instances with specific list of arguments, and that is not possible when using the
new keyword. What you must do instead is use ReflectionClass::newInstanceArgs()
to create this instance with the provided arguments.
There are two more sibling methods that can be used to create new objects, ReflectionClass::newInstanceWithoutConstructor()
and ReflectionClass::newInstance()
,
so you can also search for them when you want to count the number of objects created.