php 5.3 part 2 - lambda functions & closures

26
Lambda Functions & Closures A Sydney PHP Group Presentation 2 nd October 2008 By Timothy Chandler

Upload: melechi

Post on 10-May-2015

9.813 views

Category:

Technology


3 download

DESCRIPTION

This is Part 2 of the series about PHP 5.3. It goes into detail regarding Lambda Functions and Closures - a great new feature in PHP 5.3.

TRANSCRIPT

Page 1: PHP 5.3 Part 2 - Lambda Functions & Closures

Lambda Functions & Closures

A Sydney PHP Group Presentation2nd October 2008

By Timothy Chandler

Page 2: PHP 5.3 Part 2 - Lambda Functions & Closures

Lambda Functions– Lambda Calculus

Lambda functions originate from lambda calculus which was introduced by Alonzo Church and Stephen Cole Kleene in the 1930s.

The lambda calculus can be thought of as an idealized, minimalistic programming language. It is capable of expressing any algorithm, and it is this fact that makes the model of functional programming an important one.

The lambda calculus provides the model for functional programming. Modern functional languages can be viewed as embellishments to the lambda calculus.

Page 3: PHP 5.3 Part 2 - Lambda Functions & Closures

Lambda Functions– Implementations

Implementing the lambda calculus on a computer involves treating "functions" as “first-class objects”, which raises implementation issues for stack-based programming languages. This is known as the Funarg problem – More on this later.

Many languages implement lambda functions. These include: Python C++ C# (2 different implementations – Second one improved in C#

v3.0) JavaScript ...and many more...

Page 4: PHP 5.3 Part 2 - Lambda Functions & Closures

Lambda Functions– Implementation Examples

Python:

C++:

sPython Lambda Function

func = lambda x: x ** 2

sC++ Lambda Function

std::for_each(c.begin(), c.end(), std::cout << _1 * _1 << std::endl);

Page 5: PHP 5.3 Part 2 - Lambda Functions & Closures

Lambda Functions– Implementation Examples

C#:

C# v3.0:

sC# v3.0 Lambda Function

//Create an delegate instanceMathDelegate lambdaFunction = i => i * i;Execute(lambdaFunction);

s

C# Lambda Function//Declare a delegate signaturedelegate double MathDelegate(double i);//Create a delegate instanceMathDelegate lambdaFunction = delegate(double i) { return Math.Pow(i, 2); };

/* Passing ' lambdaFunction ' function variable to another method, executing, and returning the result of the function */double Execute(MathDelegate lambdaFunction) { return lambdaFunction(100); }

Page 6: PHP 5.3 Part 2 - Lambda Functions & Closures

Lambda Functions– Implementation Examples

JavaScript:

s

JavaScript Lambda Functionvar lambdaFunction=function(x) {

return x*10;}document.write(lambdaFunction(100));

Page 7: PHP 5.3 Part 2 - Lambda Functions & Closures

Lambda Functions– The PHP Way

PHP 5.3:

Syntax:

s

PHP 5.3 Lambda Function<?php$lambdaFunction=function($x) {

return $x*10;};print $lambdaFunction(100);?>

sLambda Function Syntax

function & (parameters) use (lexical vars) { body };

Page 8: PHP 5.3 Part 2 - Lambda Functions & Closures

Lambda Functions– The PHP Way

The goal of PHP’s Lambda function implementation is to allow for the creation of quick throw-away functions.

Don’t confuse with “create_function()”.These functions compile at “run-time”.These functions DO NOT compile at “compile-time”.Optcode caches CANNOT cache them.Bad practice.

Page 9: PHP 5.3 Part 2 - Lambda Functions & Closures

Closures

Page 10: PHP 5.3 Part 2 - Lambda Functions & Closures

Closures– The Funarg Problem

Lambda functions MUST be first-class objects.Funarg, meaning “functional argument”, is a

problem in computer science where a “stack-based programming language” has difficulty implementing functions as “first-class objects”.

The problem is when the body of a function refers to a variable from the environment that it was created but not the environment of the function call.

Standard Solutions: Forbid such references. Create closures.

Page 11: PHP 5.3 Part 2 - Lambda Functions & Closures

Closures– The PHP Funarg Problem Solution

PHP 5.3 introduces a new keyword ‘use’.Use this new keyword when creating a lambda function to

define what variables to import into the lambda functions scope – This creates a Closure.

Page 12: PHP 5.3 Part 2 - Lambda Functions & Closures

Closures– The “use” Keyword

Example:

Result:

s

Lambda Function Closure$config=array('paths'=>array('examples'=>'c:/php/projects/examples/'));$fileArray=array('example1.php','example2.php','exampleImage.jpg');

$setExamplesPath=function($file) use($config) {

return $config['paths']['examples'].$file;};

print_r(array_map($setExamplesPath,$fileArray) );

Array (

[0] => c:/php/projects/examples/example1.php[1] => c:/php/projects/examples/example2.php[2] => c:/php/projects/examples/exampleImage.jpg

)

Page 13: PHP 5.3 Part 2 - Lambda Functions & Closures

Closures– The “use” Keyword

Example:

Result:

s

Lambda Function Closure – As an Anonymous Function$config=array('paths'=>array('examples'=>'c:/php/projects/examples/')); $fileArray=array('example1.php','example2.php','exampleImage.jpg');print_r(array_map

(function($file) use($config)

{return $config['paths']['examples'].

$file;},$fileArray

));

Array (

[0] => c:/php/projects/examples/example1.php[1] => c:/php/projects/examples/example2.php[2] => c:/php/projects/examples/exampleImage.jpg

)

Page 14: PHP 5.3 Part 2 - Lambda Functions & Closures

Closures– “use” as reference or copy

Variables passed into the “use” block are copied in by default – This is the expected PHP behaviour.

You can cause a variable to be imported by reference the same way you do when defining referenced parameters in function declarations.

The PHP 5 pass by reference for objects rule still applies.

Page 15: PHP 5.3 Part 2 - Lambda Functions & Closures

Closures– “use” by reference

Example:

Why? Able to directly affect the variable from within the lambda function. If used with a large array, can prevent massive overheads. Memory efficient.

s

Referenced Variable Import

Page 16: PHP 5.3 Part 2 - Lambda Functions & Closures

Lifecycle A lambda function can be created at any point in your application, except

in class declarations. Example:

Throws Error:

s

Lambda Function in Class Declarationclass foo{

public $lambda=function(){

return 'Hello World';};public function __construct(){

print $this->lambda();}

}new foo();

Parse error: syntax error, unexpected T_FUNCTION in D:\Development\www\php5.3\lambda\5.php on line 4

Page 17: PHP 5.3 Part 2 - Lambda Functions & Closures

Lambda functions can live longer than whatever created them. Example:

Result:

s

Lifecycle Example 1class foo{

public $lambda=null;public function __construct(){

$this->lambda=function() {return 'Hello World';};}

}$foo=new foo();var_dump($foo);$lambda=$foo->lambda;unset($foo);var_dump($foo);print $lambda();

Lifecycle

object(foo)#1 (1) { ["lambda"]=> object(Closure)#2 (0) { } }NULLHello World

Page 18: PHP 5.3 Part 2 - Lambda Functions & Closures

Imported variables can also live longer. Example:

Result:

s

Lifecycle Example 2//Create prefix say function.$say=function($prefix){

return function($suffix) use(&$prefix){

print $prefix.$suffix;};

};//Create suffix say function - will loose $prefix right?$say=$say('Hello ');//Wrong! - Execute new say concatenated function.$say('World!'); //Outputs "Hello World!" <$prefix><$suffix>

Lifecycle

Hello World

Page 19: PHP 5.3 Part 2 - Lambda Functions & Closures

Methods and properties used in a closure can live longer than the object. Example:

Result:

s

Lifecycle Example 3class foo{

public $bar="Bar\r\n";public function __construct(){print "__construct()\r\n“;}public function __destruct(){print "__destruct()\r\n“;}public function getBarLambda(){

return function(){return $this->bar;};}

}$foo=new foo();$bar=$foo->getBarLambda();print $bar();unset($foo);var_dump($foo);print $bar();unset($bar);print $bar();

Lifecycle – Objects

__construct()BarNULLBar__destruct()Fatal error Function name must be a string in D:\Development\www\php5.3\lambda\8.php on line 31

Page 20: PHP 5.3 Part 2 - Lambda Functions & Closures

If a closure exists with a reference to an object’s method or property, that object is not completely destroyed when unset.__destruct() is NOT called until the closure is

destroyed.The unset object CANNOT be used in this

situation as it will be considered a null value by anything trying to access it outside the closure environment.

Lifecycle – Objects

Page 21: PHP 5.3 Part 2 - Lambda Functions & Closures

Lambda Functions are Closures because they automatically get bound to the scope of the class that they are created in.

$this is not always needed in the scope.Removing $this can save on memory.You can block this behaviour by declaring the

Lambda Function as static.

Object Orientation

Page 22: PHP 5.3 Part 2 - Lambda Functions & Closures

Object Orientation Example:

Result:

s

Static Lambda Functionsclass foo{

public function getLambda(){

return function(){var_dump($this);};}public function getStaticLambda(){

return static function(){var_dump($this);};}

}$foo=new foo();$lambda=$foo->getLambda();$staticLambda=$foo->getStaticLambda();$lambda();$staticLambda();

object(foo)#1 (0) { }NULL

Page 23: PHP 5.3 Part 2 - Lambda Functions & Closures

PHP 5.3 introduces a new magic method.Invokable objects are now possible through

the use of the __invoke() magic method.Essentially makes the object a closure.

Object Orientation

Page 24: PHP 5.3 Part 2 - Lambda Functions & Closures

Object Orientation Example:

Result:

s

Invokable Objectsclass foo{

public function __invoke(){

print 'Hello World';}

}$foo=new foo;$foo();

Hello World

Page 25: PHP 5.3 Part 2 - Lambda Functions & Closures

Questions?

Page 26: PHP 5.3 Part 2 - Lambda Functions & Closures

Thank you.

Referenceshttp://en.wikipedia.org/wiki/Lambda_calculushttp://en.wikipedia.org/wiki/Closure_(computer_science)http://en.wikipedia.org/wiki/Funarg_problemhttp://wiki.php.net/rfc/closures