Well it's high time I share a few tidbits of things that have a general purpose in PHP development but apply themselves to Magento code performance. Just a few little short things that may not seem like a lot but really do impact on your performance, especially as your Magento site begins to grow.

I also openely welcome differing opinions on anything I write and help if you have helpful knowledge. Please get in touch.

Table of contents

  1. Utilise the Magento Registry
  2. Loops
  3. Collections
  4. Thanks

Utilise the Magento Registry

I often see in code the need to load many models throughout the magento files of a custom theme and more often than not it is not needed to make more calls to the magento DB (Database). An example of said calls:

[php] $name = Mage::getModel(‘catalog/product’)->load($productId)->getName(); $sku = Mage::getModel(‘catalog/product’)->load($productId)->getSku(); $id = Mage::getModel(‘catalog/product’)->load($productId)->getId(); [/php]

These are all seperate calls to the the Database via magento models, which are taxing sql queries to call. Of course the above example could be neatened into:

[php] $product = Mage::getModel(‘catalog/product’)->load($productId); $id = $product->getId(); $sku = $product->getSku(); $name = $product->getName(); [/php]

One call now to the DB and its lessened the hit of many SQL queries but you can further this even more by utilising magento's registry pattern. Now Magento's registry pattern is three static methods in magento's mage class that work with magento's registry. Now to go into this is is better served reading alan storms fantastic blog post about it.

Now say you are wishing to pull in the current product model, it's already available in the registry:

[php] $product = Mage::registry('current_product'); $id = $product->getId(); $sku = $product->getSku(); $name = $product->getName(); [/php]

This requires no extra calls to the DB as its been saved to magento's registry, really helpful to know. Magento's registry contains lots of registered parts of data that you can use rather than making extra calls to models or collections. For a full list of what is in magento's registry then you can utilise PHP 5.3's reflections class to find out:

[php] $class = new ReflectionClass('Mage'); $prop = $class->getProperty('_registry'); $prop->setAccessible(true); $registry = $prop->getValue(); var_dump( array_keys($registry) ); [/php]

This will output all the values that you can use. Very helpful.

Loops

It might seem trivial but on small sites this may not be a huge performance boost but as sites grow to god damn proportions you will need your code to solid as a rock.

One such instance I see is counts used in for loops, like this:

[php] for($i = 0; $i < count($items); $i++) { // do some magic } [/php]

Now this is not ideal for performance even though count is quite quick but especially in a magento context that $items array is most likely going to contain a huge collection of objects and models. That count is running on each loop.

A much neater approach is a simple tweak:

[php] $count = count($items); for($i = 0; $i < $count; $i++) { // do some magic } [/php]

SQL Queries in loops

Loading a new query in a loop can start to become incredibly taxing on any large site and is something you should be weary of weary traveller. In a regular PHP context:

[php] $products = $query->fetch_assoc($sql) foreach($products as $product) { $query = $db->query('SELECT * FROM related WHERE R_ID = ' . $product["ID"]); $result = $query->fetch_assoc(); } [/php]

In a magento context:

[php] foreach ($this->getProductIds() as $productId) { $product = Mage::getModel(‘catalog/product’)->load($productId); $this->processProduct($product); } [/php]

As mentioned in the wonderful documentation by info.magento.com: Loading a model requires several heavy SQL queries to get the model.

This amplified as a magento site grows is going to cause many many problems from a performance perspective.

To make all this code more efficient, use magento's collections, they are designed by the folk at magento to query at the most efficient point in runtime so you won't be hammering your DB with multiple models being called:

[php] $collection = Mage::getResourceModel(‘catalog/product_collection’) ->addFieldToFilter(‘entity_id’, array($this->getProductIds())) ->addAttributeToSelect(array(‘name’)); foreach ($collection as $product) { $this->processProduct($product); } [/php]

Collections

Well a collection is a type of model that contains other models, quite similar to Backbone.js concept of collections and models in a collection stores all the models in a most efficient manner and then you have a set of methods you can use on the collection.

One early thing is pulling a set amount out of collections, I have seen folk utilise code such as this (yes this bad):

[php] $collection = Mage::getModel('catalog/product') ->getCollection(); $i = 0; foreach($collection as $product){ // do some collection stuff if($i === 1) break; $i++; } [/php]

More in the know folk will be aware of the methods available in collections. If you need to find out all methods in an object in magento please see the post I did on getting class methods. So one method we can use to get the first item is getFirstItem():

[php] $collection = Mage::getModel('catalog/product') ->getCollection(); $firstItem = $collection->getFirstItem(); [/php]

Now this will pull out the first item but it is still grabbing every single model to plonk into the collection, you can force magento to only load a set number:

[php] $collection = Mage::getModel('catalog/product') ->getCollection()->setPageSize(1); // we've added ->setPageSize(1) $firstItem = $collection->getFirstItem(); [/php]

And like so we have a more efficient collection.

When also retrieving attributes from a collection using the resourceModel call, you can just call all attributes to load into the collection:

[php] $collection = Mage::getResourceModel(‘catalog/product_collection’) ->addAttributeToSelect('*'); [/php]

This is handy to grab everything in the product collection but you may just need to output the products names, you can just select the name:

[php] $collection = Mage::getResourceModel(‘catalog/product_collection’) ->addAttributeToSelect('name'); [/php]

Now the collection is loading with only the name attribute.

Magento is very clever and the developers were trying to impose java conventions into the codebase so it's impressive to see and then try to utilise these tools to your best need. This article could be so much larger but a few little things that hopefully will help you on your way. thanks.

Monthly Archives: May 2015

Magento code performance Tips

Well it’s high time I share a few tidbits of things that have a general purpose in PHP development but apply themselves to Magento code performance. Just a few little short things that may not seem like a lot but really do impact on your performance, especially as your Magento site begins to grow. I

Read more

Get PHP class methods

Ever working in PHP and need to find out all the methods in an object? If you read the PHP manual you be aware of the get_class_methods helper function, its super handy for telling you what methods you have available in an object. Now I know the refelction class is far more informative but for

Read more

Sass for, each loop to generate css

Sass has some handy control directives that can be used to output css via some programming familiar syntax and constructs. I often like to have a multitude of margin and padding direction css that can be used as helper css classes that I can apply to html. Here is a tidbit to do so in

Read more