-
There are moments when you need to see the stack trace, to know how a certain point was reached. There are two native functions for that in PHP: debug_backtrace() si debug_print_backtrace. The first one returns an array and the second will print the stack trace to the screen.
The problem is that this functions must be customized for Magento, because it is very possible that when you’re running debug_backtrace() you can run out of memory before you can send the output to a log file.
Magento has a native function for that purpose: Varien_Debug::backtrace([bool $return = false], [bool $html = true], [bool $withArgs = true]). In order to send the resulting stacktrace to a log file you simply all it with:
1Mage::log(Varien_Debug::backtrace(true, false));
This technique is very useful when you need to see where an certain object is initialized, and what methods were executed up to that point.
-
The concept of closure was introduced in PHP 5.3, with the new “more traditional” syntax for anonymous functions.
PHP 5.3
In PHP 5.3, a closure will rely on the term “use”, which was passing the variables to the anonymous function, making it a closure.
The problem is that the anonymous function will only be able to access the variables that have been passed with “use”. When it comes to objects, there are passed by reference by default, but scalar variables (int, string, etc.) are passed by value, as this is the default behavior in PHP 5+:
1$scalar = 5; 2 3$closure = function () use ($scalar) { 4 return 'Scalar: ' . $scalar . PHP_EOL; 5}; 6 7echo $closure(); // Scalar: 5 8 9$scalar = 7; 10 11echo $closure(); // Scalar: 5
Another problem is that you cannot pass $this when the anonymous function is declared inside an object, so only the public method and properties can be accessed inside the closure.
PHP 5.4
In PHP 5.4 the keyword “use” is optional, and the entire environment where the function was created is available inside the function.
The advantage is that when the anonymous function is created inside another function or method, the anonymous function has access to the environment where it was created, even after the execution of the environment is over. The objects from this environment will be unset, only after the last reference to the closure will be unset:
1class testClass { 2 3 private $changeableVar = 1; 4 private $bigVar; 5 6 public function __construct() { 7 // Allocate a big variable so we can see the changes in memory 8 $this->bigVar = str_repeat("BigWord", 5000); 9 } 10 11 /** 12 * A method that returns the closure 13 */ 14 public function closure() { 15 16 return function () { 17 // Display the value of a private property of the object 18 echo 'Private property: ' . $this->changeableVar.PHP_EOL; 19 20 // Change the value of a private property of the object 21 $this->changeableVar = 2; 22 }; 23 } 24 25 /** 26 * Method that displays a private property 27 */ 28 public function showChangeableVar() { 29 echo 'Private property in method: ' . $this->changeableVar.PHP_EOL; 30 } 31 32} 33 34// Memory befor the objects is created 35echo "Memory: " . memory_get_usage() . PHP_EOL; // Memory: 229896 36 37// Create object 38$testObj = new testClass(); 39 40// Create closure 41$closure = $testObj->closure(); 42 43// Execute closure 44$closure(); // Private property: 1 45 46// Displaying the current value of the private property 47$testObj->showChangeableVar(); // Private property in method: 2 48 49// Memory befor object will be unset 50echo "Memory: ". memory_get_usage() . PHP_EOL; // Memory: 266240 51 52// Unset the object 53unset($testObj); 54 55// Memory after the object was distroyed, there is no big difference in memory 56echo "Memory: ". memory_get_usage() . PHP_EOL; // Memory: 266152 57 58// Run closure after the object in which it was created was unset 59echo $closure(); // Private property: 2 60 61// Unset closure and with it the object environment 62unset($closure); 63 64// Memotry after the las reference to the object (closure) is unset 65echo "Memory: " . memory_get_usage() . PHP_EOL; // Memory: 230416
Callable type hinting
Another new feature introduced in PHP 5.4 regarding closures is the new “type hint”: “callable”. Actually callable is referring to any anonymous function, and even to a new way of calling a method of an object:
1<?php 2 3// A function that uses type hinting 4function typeHinting(callable $a) { 5 echo $a() . PHP_EOL; 6} 7 8// A closure 9$closure = function () { 10 return __FUNCTION__; 11}; 12 13// Call the type hinting function with the closure 14typeHinting($closure); // {closure} 15 16class testClass { 17 public function testMethod() { 18 return __METHOD__; 19 } 20} 21 22// A mock object 23$testObj = new testClass(); 24 25// The new way of calling object methods 26$objCallable = array($testObj, 'testMethod'); 27 28// Call type hinting function with the new method calling way 29typeHinting($objCallable); // testClass::testMethod
I believe that only now we can really say that PHP supports closures, the right way!
-
In one of my adventures in the Magento code. I’ve encountered the following problem: I had to add a link to the breadcrumb.
As the documentation is not so great, after a little debugging (not a lot), I’ve got in to the core Mage_Page_Block_Html_Breadcrumbs.
The method is quite self-explanatory: addCrumb($crumbName, $crumbInfo, $after = false). Since I was there, I took a look inside:
1function addCrumb($crumbName, $crumbInfo, $after = false) 2{ 3 $this->_prepareArray($crumbInfo, array('label', 'title', 'link', 'first', 'last', 'readonly')); 4 if ((!isset($this->_crumbs[$crumbName])) || (!$this->_crumbs[$crumbName]['readonly'])) { 5 $this->_crumbs[$crumbName] = $crumbInfo; 6 } 7 return $this; 8}
What’s interesting is the $after parameter, as you can see, even though it has a default value, is not used anywhere. The rest work’s as expected, probably this is why people don’t complain so much about it.
-
JavaScript and PHP support both lambda functions and closures. But the terms are poorly understood in both programming languages and are often confused with each other.
Lambda functions
Also called anonymous functions. They refer to functions that can be called without being bound to an identifier. One of their purposes is to be passed as arguments. The Lambda name was introduced by Alonzo Church, inventor of lambda calculus in 1936. In lambda calculus all functions are anonymous.
JavaScript
In JavaScript lambdas are part of the standard set and there are the preferred method of defining functions.
For instance:
1var add = function (a, b) { 2 return a + b; 3} 4alert(add(1, 2)); // 3
Lambda functions are used almost in any context when it comes to JavaScript, like:
1window.onload = function (e) { 2 alert('The page has loaded!'); 3}
PHP
In PHP, lambda functions were introduced in version 4.0.1 using create_function. In version 5.3+ a similar syntax to JavaScript was added, a much more readable and elegant way of defining a function.
This means that in PHP there are two ways of creating a lambda function:
1// PHP 4.0.1+ 2$add = create_function('$a, $b', 'return $a + $b;'); 3 4// vs. 5 6// PHP 5.3+ 7$add = function ($a, $b) { 8 return $a + $b; 9}; 10 11echo $a(1,2); // 3
Lambda functions can be used as parameter for other functions, such as usort:
1$array = array(4, 3, 5, 1, 2); 2usort($array, function ($a, $b) { 3 if ($a == $b) { 4 return 0; 5 } 6 return ($a < $b) ? -1 : 1; 7});
Even more, PHP 5.3+ allows calling an object as a anonymous function:
1class test { 2 function __invoke($a) { 3 echo $a; 4 } 5} 6$a = new test(); 7$a('test'); // 'test'
Closures
The closure is really the misunderstood concept of the two. In general confusion appears because closures may involve lambda functions. A closure refers to the ability of a function/object to access the scope in which it was created even if the parent function has ended it’s execution and returned. In other words, the function/object returned by a closure is running in the scope in which it was defined.
In JavaScript the notion of closure is part of the standard arsenal, because the language is not based on the traditional object model, but rather on prototypes and functions. But JavaScript has some traditional object model parts, like the fact that you can use “new” to construct an object based on a function that plays the role of a class. In PHP closures are more of an new way to approach problems, because PHP is part of the traditional object model family.
JavaScript
In JavaScript the notion of closure is widely used, it’s so popular because JavaScript is not a traditional object orientated language, but rather a functional one, based on prototype inheritance.
JavaScript doesn’t have Public, Private and Protected, but rather only Public and Private and objects an inherit from each other, without using classes.
Another issue is the scope, because the global scope is used by default. This issues can be fixed in an elegant fashion using closures:
1var closure = function () { 2 var sum = 0; 3 return { 4 add: function (nr) { 5 sum += nr; 6 }, 7 getSum: function () { 8 return sum; 9 } 10 } 11}(); 12 13closure.add(1); 14closure.add(2); 15console.log(closure.getSum());
In the example above, sum is a private property and in theory can only be accessed and modified by the closure function. The interesting part is that the parentheses from the end of the function definition, signify that this function will be immediately executed and therefore will return the result which is an object. At this point the original function will only exist for serving the return object, encapsulating therefor the private variable.
Although the function has finished execution, through this closure the returned object can still access the variables defined in the function scope, because that was the environment in which it was created.
This becomes even more interesting when a function returns another function:
1var counter = function () { 2 var counter = 0; 3 console.log('in closure'); 4 return function () { 5 console.log('in the anonymous function'); 6 return ++counter; 7 }; 8}; 9var counter1 = counter(); 10 11console.log(counter1()); // 1 12 13var counter2 = counter(); 14console.log(counter2()); // 1 15console.log(counter1()); // 2
The output will be:
1in closure 2in the anonymous function 31 4in closure 5in the anonymous function 61 7in the anonymous function 82
What actually happens is that the first function is executed and returns an anonymous function that can still access the environment in which it was created. In my opinion this is where the confusion between closures and lambda functions comes from, because a function returns another function.
The difference between examples is that in the first one the closure function executes immediately, and in the second example when counter is executed it’s returning a result that is actually a function definition, which in turn can be executed. Of course the second example can be modified to act just like in the first example using parenthesis.
PHP
As I said above, the notion of closure in PHP is not as important as in JavaScript.
Considering that lambda functions are available in the language since version 4, closures only appeared with PHP 5.3+.
Because of the block scope nature of PHP, there is a better encapsulation but there is a lot less flexibility compared to JavaScript. Basically in PHP you must specify using the use instruction what will the anonymous function be able to access from the closure scope.
1function closure () { 2 $c = 0; 3 return function ($a) use (&$c) { 4 $c += $a; 5 echo $a . ', ' . $c . PHP_EOL; 6 }; 7} 8 9$closure = closure(); 10 11$closure(1); 12$closure(2);
Unlike JavaScript, in PHP closures can not return objects, or rather the object can not be bound to the scope in which it was created, unless you send the variables as a reference to the constructor, in which case is not very elegant and I can’t imagine a scenario that would absolutely need closure for this.
Like in the JavaScript examples, instead of parentheses “()” at the end of the function, in PHP to run a function immediately after defining it call_user_func() or call_user_func_array() can be used:
1$closure = call_user_func(function () { 2 $c = 0; 3 return function ($a) use (&$c) { 4 $c += $a; 5 echo $a . ', ' . $c . PHP_EOL; 6 7 }; 8}); 9 10$closure(1); 11$closure(2);
-
Why “ini” files? Because there are more convenient! Most servers in the *nix world have “ini” or “conf” configuration files. In the PHP world there are preferred PHP configuration files, which are usually arrays. Wouldn’t be more elegant to have an ini file without PHP code in it?
Fortunately PHP has a couple of native functions just for that: parse_ini_file and parse_ini_string.
The principle is very simple, you give an configuration ini file as a parameter and it will return an array.
A little example:
1;config.ini 2 3[simple] 4number = 1 5another = 2 6fraction = 0.2 7 8[escape] 9path = /usr/bin/php 10url = https://blog.claudiupersoiu.ro 11error = '<a href="%path%">%error%</a>' 12 13[array] 141 = a 152 = b 163 = c
To parse the previous file:
1$config = parse_ini_file('config.ini', true); 2var_dump($config);
The second parameter specifies if the sections will become keys in the resulting array. Honestly I don’t think of a case when that wouldn’t be useful.
Seems slow? In fact for the file above is faster to parse then to include an array already parsed. The difference on my computer is ~0.00002s.
But the above file is not exactly big, so let’s get to a more serious ini file, like php.ini. Here the difference was bigger in favor of array, which won whit an advantage of ~0.0003, which means about half of parsing time that was ~0.0006s.
Taking into consideration that my computer is pretty fast and concurrent request can add an overhead for big files, sometimes it is useful to use a cache of the ini file.
Fortunately this is easy to do in PHP.
1$cache = var_export($config, true); 2 3file_put_contents('cache/config.php', "<?php\n\$config = " . $cache . ';');
Now you just need to include cache/config.php file and of course regenerate it when something changes in the ini file.
PHP should have write permissions for the cache directory.