Link to home
Start Free TrialLog in
Avatar of rgb192
rgb192Flag for United States of America

asked on

second question about sale method

Avatar of rgb192
rgb192
Flag of United States of America image

ASKER

Yes. I asked a question on that thread.
Avatar of rgb192

ASKER

I closed the previous question because expert gave answer to original question.  But on this link (this question) I have another question.
Avatar of gr8gonzo
Now, my own reply to that question is that there is only one run in the foreach because there is only one function referenced in that array.

A lambda function is basically one that gets created by code when the script runs, rather than a function that is written in the code itself:

// A lambda function
$a_lamba_function = create_function( '$foo', 'print "{$foo}";' );

// A regular function
function bar($foo)
{
   print "{$foo}";
}

Open in new window


Both of the functions do exactly the same thing - they take in the parameter $foo and print it to the screen. The only difference is that the regular function is already written by you in advance and so the PHP compiler knows about it and how to run it when the script starts. The lambda function, however, doesn't exist until you run the create_function() line of code.

Now, in your code, you create one lambda function and then you tell the processor about it once:

$processor->registerCallback( $logger );

Open in new window

So now, whenever the processor does a sale, it will run that lambda function once for that sale.

So when you run sale on two products:
$processor->sale( new Product( "shoes", 6 ) );
print "\n";
$processor->sale( new Product( "coffee", 6 ) );

...it will run the lambda function once on the shoes product. Then when you run it again on the coffee product, it will again go through foreach() and only run the lambda function once.

If you copied that registerCallback line and ran it twice:

$processor->registerCallback( $logger );
$processor->registerCallback( $logger );

Open in new window


...then any time sale() was run, it would run the logger function twice for that product.
Avatar of rgb192

ASKER

Sorry about confusing question.

there is only one run in the foreach because there is only one function referenced in that array.
Which one. What is being run?  I just see lambda$x.   Why is each $processor->sale( new Product( "shoes", 6 ) ); a lambda function?

The only difference is that the regular function is already written by you in advance and so the PHP compiler knows about it and how to run it when the script starts. The lambda function, however, doesn't exist until you run the create_function() line of code.
Is this 'late binding' or 'late static binding'?


If you copied that registerCallback line and ran it twice:
I ran 3 times and each shoes and coffee were echoed 3 times each

<?php
require_once( "closures.php" );

$logger = create_function( '$product', 
                           'print "    logging ({$product->name})\n";' );

$processor = new ProcessSale();
$processor->registerCallback( $logger );
$processor->registerCallback( $logger );
$processor->registerCallback( $logger );

//$processor->sale( new Product( "shoes", 6 ) );
$temporary_variable=new Product("shoes", 6);
$processor->sale($temporary_variable);
print "\n";
$processor->sale( new Product( "coffee", 6 ) );
?>

Open in new window

shoes: processing logging (shoes) logging (shoes) logging (shoes) coffee: processing logging (coffee) logging (coffee) logging (coffee)


Is the array saved in the function allowing both shoes and coffee to be run 3x?
Why is each $processor->sale( new Product( "shoes", 6 ) ); a lambda function?

That isn't the lambda function. The lambda function is $logger:

$logger = create_function( '$product', 
                           'print "    logging ({$product->name})\n";' );

Open in new window


It might be confusing because in the code, you see the function as $logger, but inside PHP's brain, it keeps track of lambda functions in a separate table and it calls them "lambda_#" like lambda_1, lambda_2, and so on. So $logger is just a variable that references the function that PHP calls lambda_8.

Imagine you are hired to be a salesperson in a store. Every morning, you are given the same list of instructions of how to make a sale:

1. Scan the item.
2. Slide a credit card in the credit card machine.
3. Give the receipt and the item to the buyer.

Every day, you are doing the same three things over and over again every time you make a sale, and you know these things really well because they are predefined instructions. You could turn the above into something that looks like this:

class Salesperson
{
  function sale($item,$credit_card,$buyer)
  {
    $this->scan_item($item);
    $receipt = $this->swipe_credit_card($credit_card);
    $this->give_receipt_and_item($receipt, $item, $buyer);
  }

  function scan_item($item)
  {
    // scan the item
  }

  function swipe_credit_card($card)
  {
    // send credit card data and get a receipt back
    return $receipt;
  }

  function give_receipt_and_item($receipt, $item, $buyer)
  {
    // give the stuff to the person who is buying the item
  }
}

Open in new window


Now let's say that halfway through your day, your boss comes up and tells you, "I want you to start telling customers 'Thank you, THEIR NAME, for shopping with us!' after you give them the receipt."

This is just the boss's wishes, but it's not an official employee rule, so it's not written in the instructions that you get each day.

You can think of your boss's request as a "lambda" function - something that simply comes up in the middle of the day. It could look like this:

$say_thank_you = create_function('$name', 'print "Thank you, {$name}, for shopping with us!";');

Open in new window


However, the sale method that I showed you above doesn't have any way to simply call the lambda function. It is strictly the same three functions over and over again.

So one way of doing this is to save an array into the Salesperson object and have that array hold onto any additional requests that your boss asks you to do:

class Salesperson
{
   private $special_boss_requests = array();

   ....rest of the code...

}

Open in new window


...but now you need a way to add to that array. You could either make the array public or the more "elegant" or "proper" way would be to add a method that manages the requests:

class Salesperson
{
   private $special_boss_requests = array();

   public function add_boss_request($request)
   {
     // Add the request to the list of things to do
     $this->special_boss_requests[] = $request;
   }

   ....rest of the code...

}

Open in new window


Finally, you need to update the sale so that you actually perform the boss's requests:

class Salesperson
{
   private $special_boss_requests = array();

   public function add_boss_request($request)
   {
     // Add the request to the list of things to do
     $this->special_boss_requests[] = $request;
   }

  function sale($item,$credit_card,$buyer)
  {
    $this->scan_item($item);
    $receipt = $this->swipe_credit_card($credit_card);
    $this->give_receipt_and_item($receipt, $item, $buyer);
    
    // Now perform all the boss's special requests, passing the buyer's name to each one
    foreach($this->special_boss_requests as $request)
    {
       call_user_func($request, $buyer); 
    }
  }

   ....rest of the code...

}

Open in new window


So now you might see something like this:

// Start your day
$me = new Salesperson(); 

// You sell a pair of shoes to Joe Smith
$me->sale("shoes", "Joe Smith's credit card", "Joe Smith");

// ########################################################
// At this point, you're not saying thank you yet.
// ########################################################

// The boss comes up with the idea to say thank you (which is our lambda function)
$say_thank_you = create_function('$name', 'print "Thank you, {$name}, for shopping with us!";');

// The boss tells you to do it
$me->add_boss_request($say_thank_you);

// ########################################################
// Now when you perform a sale...
// ########################################################

// Sell some coffee to Mary Smith
$me->sale("coffee", "Mary Smith's credit card", "Mary Smith"); 

// ########################################################
// After doing everything, you say, "Thank you, Mary Smith, for shopping with us!"
// ########################################################

// Now the boss comes up with another idea - make sure you also tell them about our website!

// The boss comes up with the idea to say thank you (which is our lambda function)
$say_website_reminder = create_function('$name', 'print "Also, {$name}, make sure you visit our website at www.lambdashopping.com!";');

// The boss tells you to do it
$me->add_boss_request($say_website_reminder);

// ########################################################
// At this point, you now have $say_thank_you and $say_website_reminder in your special boss requests array, so any time you make a sale from this point on, you will say both things.
// ########################################################

// Sell a car to George Smith
$me->sale("car", "George Smith's credit card", "George Smith");

// ########################################################
// Now George Smith should get hear both things at the end.
// ########################################################

Open in new window


Overall, yes, this is considered late binding or dynamic binding, because the functions are being created after the code starts, and then being looked up and called by dynamic code.
Avatar of rgb192

ASKER

<?php
class Salesperson
{
  private $special_boss_requests=array();
  
  public function add_boss_requests($request)
  {
    //add the request to the list of things to do
    $this->special_boss_requests[]=$request;
  }
  
  function sale($item,$credit_card,$buyer)
  {
    $this->scan_item($item);
    $receipt = $this->swipe_credit_card($credit_card);
    $this->give_receipt_and_item($receipt, $item, $buyer);
    //now perform all the boss's special requests, passing the buyer's name to each one
    foreach($this->special_boss_requests as $request){
      call_user_func($request,$buyer);
    } 
  }

  function scan_item($item)
  {
    // scan the item
  }

  function swipe_credit_card($card)
  {
    // send credit card data and get a receipt back
    return $receipt;
  }

  function give_receipt_and_item($receipt, $item, $buyer)
  {
    // give the stuff to the person who is buying the item
  }
}

//start your day
$me=new Salesperson();
//you sell a pari of shoes to joe smith
$me->sale("shoes","joe smith credit card","Joe Smith");
//at this point you are not saying thank you yet
//the boss comes up with idea to say thank you which is our lambda function
$say_thank_you=create_function('$name','print "Thank you,{$name} for shopping with us!";');
//the boss tells you to do it
$me->add_boss_requests($say_thank_you);
//now when you perform a sale...
//sell coffee to mary smith
$me->sale("coffee", "mary smith credit card", "mary smith");
//after doing everying you say, thank you mary smith for shopping with us
//now the boss comes up with another idea-make sure you also tell them about our website
//the boss comes up with idea to say thank you which is our lambda function
$say_website_reminder=create_function('$name','print "Also{$name}, make sure you visit our website";');
//the obss tells you to do it
$me->add_boss_requests($say_website_reminder);
//at this point you now have $say_thank_you and say_website_reminder
//sell a car to george smith
$me->sale("car", "george smith credit card","george smith");
//now george smith should hear both at the end

Open in new window


Notice: Undefined variable: receipt in C:\Users\Acer\Documents\NuSphere PhpED\Projects\noname322.php on line 31

Notice: Undefined variable: receipt in C:\Users\Acer\Documents\NuSphere PhpED\Projects\noname322.php on line 31
Thank you,mary smith for shopping with us!
Notice: Undefined variable: receipt in C:\Users\Acer\Documents\NuSphere PhpED\Projects\noname322.php on line 31
Thank you,george smith for shopping with us!Alsogeorge smith, make sure you visit our website


I think swipe card was not used to return variable or populate $this->receipt

I think I understand the anonymous method create_function (adding many bosses tasks to an existing class without altering the the class) It may be above my skill level.
ASKER CERTIFIED SOLUTION
Avatar of gr8gonzo
gr8gonzo
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial