12
function convert($currencyType)
{
    $that = $this;
    return $result = function () use ($that) 
    {
        if (!in_array($currencyType, $this->ratio))
                return false;

        return ($this->ratio[$currencyType] * $this->money); //a float number
    };
}

$currency = new Currency();
echo $currency->convert('EURO');

What's wrong?

I'm getting the error message:

Catchable fatal error: Object of class Closure could not be converted to string
Lisa Miskovsky
  • 896
  • 2
  • 9
  • 18
  • 5
    Your `convert()` function returns a function. Then you're trying to coerce it into a string by `echo()`ing it. – landons Mar 12 '13 at 22:01
  • But the closure returns a float/false to the $result? – Lisa Miskovsky Mar 12 '13 at 22:02
  • And your `$this` references inside the Closure should be `$that` instead. They might have changed that in 5.4 thought; not sure. – landons Mar 12 '13 at 22:02
  • You would actually have to call the resulting closure to get the float. Why are you using a closure here? – landons Mar 12 '13 at 22:03
  • Ah. Lemme give you a formal answer... – landons Mar 12 '13 at 22:04
  • The closure is a function, which is never called here... Unfortunately PHP (5.3 at least) can't do the required `echo $currency->convert('EURO')();` here, so it'd have to be `$callback = $currency->convert('EURO'); echo $callback();`, but _why_ use a closure in the first place? – Wrikken Mar 12 '13 at 22:05
  • I've just replied this question above. It's for learning purposes. I just want to do it with closures. – Lisa Miskovsky Mar 12 '13 at 22:06

4 Answers4

8

Couple of issues:

  1. Because you're returning a closure, you have to first assign the closure to a variable, and then call the function
  2. Your $this references won't work inside a closure (which is why you're useing $that instead)
  3. You need to also use $currencyType to access it in the closure's scope

function convert($currencyType)
{
    $that =& $this; // Assign by reference here!
    return $result = function () use ($that, $currencyType) // Don't forget to actually use $that
    {
        if (!in_array($currencyType, $that->ratio))
                return false;

        return ($that->ratio[$currencyType] * $that->money); //a float number
    };
}

$currency = new Currency();
$convert = $currency->convert('EURO');
echo $convert(); // You're not actually calling the closure until here!
landons
  • 9,502
  • 3
  • 33
  • 46
  • One question, though. Why if (!in_array($currencyType, $that->ratio)) return false; always returns false? $currencyType = 'EURO' and print_r($that->ratio) correctly outputs the array. – Lisa Miskovsky Mar 12 '13 at 22:17
5

You have to make function between parentheses and add parentheses when closing the function.

function convert($currencyType)
{
    $that = $this;
    return $result = (function () use ($that) 
    {
        if (!in_array($currencyType, $this->ratio))
                return false;

        return ($this->ratio[$currencyType] * $this->money); //a float number
    })();
}

$currency = new Currency();
echo $currency->convert('EURO');
chakroun yesser
  • 1,407
  • 1
  • 12
  • 18
3

Just delete the return there and do:

$result = function () use ($that) 
{
    if (!in_array($currencyType, $this->ratio))
            return false;

    return ($this->ratio[$currencyType] * $this->money); //a float number
};
return $result();

Also, are you realizing you are not using $that inside the function?

By the way, why do you need an anonymous function there? Just do:

function convert($currencyType)
{
    if (!in_array($currencyType, $this->ratio))
        return false;

    return ($this->ratio[$currencyType] * $this->money); //a float number
}
Shoe
  • 74,840
  • 36
  • 166
  • 272
  • I'm trying to do it with closures. I know it's not necessary because I can do it without closures myself. I just want to use closures for learning purposes. – Lisa Miskovsky Mar 12 '13 at 22:08
  • @LisaMiskovsky, closures can be stored in variables. Therefore `$var = function() {...}` will store that function in a variable. This is just not the place where to use anonymous functions. Don't learn bad things from the start. When you'll need closure you'll know how to use them. – Shoe Mar 12 '13 at 22:09
  • Can you give me an example where it is a good place to use closures? – Lisa Miskovsky Mar 12 '13 at 22:20
  • @LisaMiskovsky [Just take a look at here](http://stackoverflow.com/questions/4147400/why-use-anonymous-function). – Shoe Mar 12 '13 at 22:24
  • I was hoping to be able to use closures similar to blocks in Ruby, e.g. rather than doing say ```if($that=='foo') $this='bar'; elseif($that=='dee') $this='dum';``` write it as: ```$this = function() { if($that=='foo') return 'bar'; elseif($that=='dee') return 'dum'; }``` except its nowhere near as concise as Ruby would be: ```ruby this = { if that='foo' then 'bar' elsif that='dee' then 'dum' }``` – Adamski Sep 10 '14 at 10:50
0
class Currency {
    function convert($currencyType)
    {
        if (!in_array($currencyType, $this->ratio))
             return false;
        return ($this->ratio[$currencyType] * $this->money); //a float number
    }
}

$currency = new Currency();
echo $currency->convert('EURO');

You are defining a lambda function. You don't need it. Also, you should be using bcmul() if this is to have any kind of accuracy; floats in PHP will give you funky results.

Matt
  • 1,287
  • 2
  • 11
  • 25