3

I have created an API integration with a third-party retailer. I have created my own Mage::dispatchEvent calls before and after the communication. I mostly use these for logging/debug mode, but I now have the opportunity to use them to manipulate data from another, loosely related module that would also use this API.

In the below example is it possible to manipulate $post_string in this local scope based on what my observer may do?

Mage::dispatchEvent('my_api_delete_before', array('post_string'=>$post_string, 'my_cart'=>$this));

$result = $this->doApiCommunication($post_string);

Mage::dispatchEvent('my_api_delete_after', array('post_string'=>$post_string, 'result'=>$result, 'product'=>$product, 'cart_item_id'=>$_item->cartItemId));
5

If $post_string is a string, then no. Changes done to it in the observer class would not be shown in this scope because strings aren't passed by reference to functions.

There are several solutions for that:

Quick but not recommended:

PHP does give you a workaround, by forcing the string to be passed by reference to the function by adding an & before the the variable name, like so:

Mage::dispatchEvent('my_api_delete_before', array('post_string'=>&$post_string, 'my_cart'=>$this));

But the reason this isn't recommended, as @dedmeet said in his comment:

using call-time pass-by-reference is not supported since PHP version 5.4.0

Directly from the PHP manual:

Note: There is no reference sign on a function call - only on function definitions. Function definitions alone are enough to correctly pass the argument by reference. As of PHP 5.3.0, you will get a warning saying that "call-time pass-by-reference" is deprecated when you use & in foo(&$a);. And as of PHP 5.4.0, call-time pass-by-reference was removed, so using it will raise a fatal error.

So here is how to do it in a way that is

Cleaner and recommended:

A better solution would be to create a Varien_Object because classes are always passed by reference. And any class that extends Varien_Object and the Varien_Object itself, gives you the ability to use the getters and setters you find around Mangento.

$obj = new Varien_Object();

// Set a value for data variable
$obj->setFoo($bar);

// The previous function is the same as the following:
// In fact, the previous function will call setData with 'foo' and $bar as its paramteres
$obj->setData('foo', $bar);

// To get the value of 'foo' you will need to call any of the following functions:
$obj->getFoo();

$obj->getData('foo');    

So to implement the Varien_object in the OP's example:

class Foo_Bar_Model_Communicator{

    public function someFunction(){
        /*
         * Assuming that $post_string is getting set here somehow
         * before the next line.
         */
        $eventData = new Varien_Data();

        $eventData->setData('post_string', $post_string);   
        $eventData->setData('cart', $this); 

        Mage::dispatchEvent('my_api_delete_before', array('event_data'=>$eventData));

        /* In this case, since we sent a Varien_Object as parameter,
         * whatever the Observer class does to the object, will be reflected
         * here as well.
         * We only need to make sure that we get the string back from the
         * Varien_Object instead of using $post_string.
         */
        $new_post_string = $eventData->getData('post_string');

        $result = $this->doApiCommunication($new_post_string);

        /*
         * We can do the same for the parameters for the next event, but it
         * wasn't part of the OP's question and it won't be needed since
         * there is no code following the dispatch event.
         *
         * However it would be a better idea to make the "before" & "after"
         * events have the same type of parameters which would be less 
         * confusing later on.
         */

        Mage::dispatchEvent('my_api_delete_after', array('post_string'=>$post_string, 'result'=>$result, 'product'=>$product, 'cart_item_id'=>$_item->cartItemId));
    }
}
  • 2
    This could be a good argument for creating $post_string as a Varien_Object, then, I assume. – philwinkle Apr 4 '13 at 16:57
  • 1
    Note: This is dependant on your php version. see php.net/manual/en/language.references.pass.php There is no reference sign on a function call - only on function definitions. Function definitions alone are enough to correctly pass the argument by reference. As of PHP 5.3.0, you will get a warning saying that "call-time pass-by-reference" is deprecated when you use & in foo(&$a);. And as of PHP 5.4.0, call-time pass-by-reference was removed, so using it will raise a fatal error. Thus, if your module is used in a later php version, you will have problems. – ProxiBlue Apr 5 '13 at 12:49
  • @philwinkle write this as an answer! Or Dan, change your answer, avoiding references is good in PHP, because they are counterintuitive. Use a Varien_Object instead and you have the full control over the object. – Fabian Blechschmidt Apr 6 '13 at 15:04
  • 1
    @FabianBlechschmidt done. @dedmeet Thanks for the warning, I've edited the answer to use a Varien_Object instead, and left the old way for reference. @philwinkle Please view the edited answer. – Dan Apr 8 '13 at 17:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.