I want to loop over an array of product IDs in Magento. In the loop I am displaying some custom attributes of the products as:
foreach ($products as $product
Mage::getModel() will always return a new Object for the given model:
/**
* Retrieve model object
*
* @link Mage_Core_Model_Config::getModelInstance
* @param string $modelClass
* @param array|object $arguments
* @return Mage_Core_Model_Abstract|false
*/
public static function getModel($modelClass = '', $arguments = array())
{
return self::getConfig()->getModelInstance($modelClass, $arguments);
}
Mage::getSingleton() will check whether the Object of the given model already exists and return that if it does. If it doesn't exist, it will create a new object of the given model and put in registry that it already exists. Next call will not return a new object but the existing one:
/**
* Retrieve model object singleton
*
* @param string $modelClass
* @param array $arguments
* @return Mage_Core_Model_Abstract
*/
public static function getSingleton($modelClass='', array $arguments=array())
{
$registryKey = '_singleton/'.$modelClass;
if (!self::registry($registryKey)) {
self::register($registryKey, self::getModel($modelClass, $arguments));
}
return self::registry($registryKey);
}
In your case you always want a completely new Product object/model since every product is unique...
getModel
will return a new instance of the requested model every time.
getSingleton
will always return the same instance. It's the implementation of the Singleton design pattern for Magento.
There is also an other aspect that you have to keep in mind. The load
method does not remove all the data you have set on the product instance. For example if you do this:
$model = Mage::getModel('catalog/product')->setData('some_field_that_does_not_exist', 1);
$model->load(3);
echo $model->getData('some_field_that_does_not_exist'); //this prints 1
This is the case for you. By using getSingleton
the second time, you get the same product instance as the first time. And when calling load
the value for credits
is not overwritten because there is no such value on the newly loaded product.
Conclusion: Do not use getSingleton
. Use getModel
. Or if you want to use getSingleton
use $model->setData(array())
before calling load
. This will reset all the attributes.
First of all I would like to explain the difference between Mage::getSingleton() and Mage::getModel() functions.
When you call the function Mage::getSingleton('catalog/product')
magento will search in the memory whether there is any object available. If not it will create a new object for Mage_catalog_Model_product
class. In the first iteration of the foreach loop this happens. But from the second iteration when magento searches in memory for Mage_catalog_Model_product class object it will find the object which was called in the first iteration. So magento won't create any new object and instead it will call the same object which is already in the memory.
BUT,
If you use Mage::getModel('catalog/product)
this function always creates new object of Mage_catalog_Model_product
class in the memory whenever you called it. So in the loop this function will create one object per iteration.
You´ll find the difference between getModel() and getSingleton() in the other answers.
But if you want to speed up your code, assuming you have a collection, do the following:
$products->addAttributeToSelect('credits');
foreach ($products as $product) {
echo '<br>' . $product->getCredits();
}
So you don´t have to load every product, which is very time-consuming.
you use Singleton when you want only one instance of an object in whole application. So when you use getSingleton it always returns the same object that can have some data loaded earlier.
So in this case when the loop starts it create new object (of course only if this was not done before in some other place in magento) and loads the data for $product['id']. In next loop iteration it takes the same object with previous product id data and loads to it new $product['id'] data. This is why there can be some problems.
If you want to have two different products you must use getModel.