-
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.
-
Three days ago, that is on 28-06-2011 the PHP 5.4 alfa 1 version was announced on ww.php.net!
Basically in this release are the things that were made for PHP 6 and did not make it in PHP 5.3, next to some other new features.
Some of the most interesting new features are:
Traits
A new OOP feature. Basically for horizontal code reuse, that is inheriting of methods instead of extending classes.
1trait Inharitable { 2 public function test() { 3 echo 'Class: ' . __CLASS__ . ' Method: ' . __METHOD__ . PHP_EOL; 4 } 5} 6 7class A { 8 use Inharitable; 9} 10 11class B { 12 use Inharitable; 13} 14 15$a = new A(); 16$a->test(); //Class: Inharitable Method: Inharitable::test 17 18$b = new B(); 19$b->test(); //Class: Inharitable Method: Inharitable::test
Traits in PHP 5.4 are the new namespaces of PHP 5.3, that is the most interesting feature in PHP 5.4.
Scalar type hinting
Up to PHP 5.3 there was type hinting only for classes, interfaces and arrays. With PHP 5.4 type hinting can be used for scalar data types like: int, string, float, book and resource.
1function test(string $var) { 2 echo $var; 3} 4 5$a = 'aa'; 6test($a);
Unfortunately on this alpha version on my computer I get: Catchable fatal error: Argument 1 passed to test() must be an instance of string, string given, called in .. on line 58 and defined in … on line 52
What can I say… it is still an alpha…
Closures
Yes, I know, there are closures in PHP 5.3 too, but there are not the same. In PHP 5.3 if you wanted a closure you had to use the keyword use and then specify the variables that the lambda functions will have access to.
In PHP 5.4 it’s beginning to look more like JavaScript, in a good way:
1class closureTest { 2 3 private $a; 4 5 function test() { 6 $this->a = 'object var'; 7 return function () { 8 echo $this->a; 9 }; 10 } 11} 12 13$a = new closureTest(); 14$b = $a->test(); 15$b(); // object var 16unset($a); 17$b(); // object var
Closure in the right way, with a lambda function the way it should be! Just like lambda functions existed even before PHP 5.3, but only after the new syntax they’ve become popular, now there was closures time.
This are some of the things that I find most interesting, but there are only a part of the new features that PHP 5.4 brings!
It’s likely that before the end of this year the final version will be ready.
I’m curious if with the final version of PHP 5.4 a new certification will come out, taking in consideration that the changes are not major.
-
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.
-
Somewhere in the certification guide there is a chapter dedicated to “streams”.
A small part of it represents the input, output and error streams from PHP. C/C++ has famous stdio.h library, but few people knows that input from keyboard is possible in PHP too.
In short, this can be achieved with PHP://STDIN, PHP://STDOUT and PHP://STDERR.
As this subject is panicking a lot of developers that are studding for ZCE, let’s get the confusion out. A stream represents a flow of information, just like when your reading and internal or external file using fopen.
But as a programmer best understands from cod, let’s get to more practical stuff.
Input
For input there is PHP://STDIN.
The next script is reading input from the keyboard:
1#!/usr/bin/php 2<?php 3// initializing the input stream 4$input = fopen('php://stdin', 'r'); 5 6// welcome message 7echo 'Type "exit" and then enter to exit' . PHP_EOL; 8 9// reading the stream input 10while($line = fgets($input, 1024)) { 11 // exit condition with line terminator 12 if($line == 'exit' . PHP_EOL) { 13 echo 'bye bye' . PHP_EOL; 14 break; 15 } 16 // displaying the input from the keyboard 17 echo 'You say: ' . $line . PHP_EOL; 18} 19 20// close stream 21fclose($input);
The first line of code is specially for Linux/Unix, and Windows users can remove it.
The cod above must be placed in to a file, like for instance testStream.php.
You must have execution rights for that file, witch can be achieved with:
1chmod +x testStream.php
Then the file can be executed in Linux directly with:
1$./testStream.php
In Windows you must give the absolute path to PHP, if the path is not already in the system include path:
1>c:\php\php.exe testStream.php
Notice that the input is with “\n” or “\r\n” at the end of the line, that’s why I’m testing “exit” with the line terminator (PHP_EOL). I’m using PHP_EOL so it can work with both Linux/Unix and Windows.
Output
For output there is PHP://STDOUT.
Unlike input, the output is a lot less relevant. Basically the output is the standard one which can be achieved with echo and print.
But for educational purpose let’s modify the previous file to use PHP://STDOUT:
1#!/usr/bin/php 2<?php 3// initializing the input stream 4$input = fopen('php://stdin', 'r'); 5 6// initializing the output stream 7$output = fopen('php://stdout', 'w'); 8 9// welcome message 10fwrite($output, 'Type "exit" and then enter to exit' . PHP_EOL); 11// reading the steam input 12while($line = fgets($input, 1024)) { 13 // exit condition with line terminator 14 if($line == 'exit' . PHP_EOL) { 15 fwrite($output, 'bye bye' . PHP_EOL); 16 break; 17 } 18 // displaying the input from the keyboard 19 fwrite($output, 'You say: ' . $line . PHP_EOL); 20} 21 22// close input stream 23fclose($input); 24 25// close output stream 26fclose($output);
Basically there isn’t any change in the script, is just that the output was displayed using PHP://STDOUT explicitly.
Error
A more interesting subject then the output is the error stream.
Basically is more relevant in the Unix/Linux environment, probably is relevant in Windows too but I don’t know how to capture it. If your reading this blog and you know how to do this please leave a comment below.
And again let’s change the script so that error messages will use the proper stream. I’ll output an error each time the user enters more then 5 characters (I’m sorry but I don’t have a lot of ideas right now):
1#!/usr/bin/php 2<?php 3// initializing the input stream 4$input = fopen('php://stdin', 'r'); 5 6// initializing the output stream 7$output = fopen('php://stdout', 'w'); 8 9// initializing the error stream 10$err = fopen('php://stderr', 'w'); 11 12// welcome message 13fwrite($output, 'Type "exit" and then enter to exit' . PHP_EOL); 14 15// reading the steam input 16while($line = fgets($input, 1024)) { 17 // exit condition with line terminator 18 if($line == 'exit' . PHP_EOL) { 19 fwrite($output, 'bye bye' . PHP_EOL); 20 break; 21 } 22 23 if(strlen($line) > 5) { 24 fwrite($err, 'WARNING! Input greater then 5 characters: ' . $line); 25 continue; 26 } 27 28 // displaying the input from the keyboard 29 fwrite($output, 'Ai scris: ' . $line . PHP_EOL); 30} 31 32// close input stream 33fclose($input); 34 35// close output stream 36fclose($output); 37 38// close error stream 39fclose($err);
By default in Linux error messages are displayed to the screen, but there are scenarios when the errors are redirected for instance to a log file .
To redirect the error messages to a log file 2>> is used like in the following example:
1$./testStream 2>>testStream.log
Input from PIPE (|)
Let’s take the fallowing scenario: the output of a previous operation contains a serious of email addresses that are both valid and invalid. There should be two files: valid.txt with valid addresses and invalid.txt with invalid ones. The email addresses will be send to the script using pipe.
The list of email addresses will be simulated using a file called email.txt:
1valid_addres@yahoo.com 2another_valid@yahoo.co.uk 3invalid@y.c 4good@gmail.com 5invalid addres@hotmail.com 6foo
The name of the script will be emailTest.php:
1#!/usr/bin/php 2<?php 3// initializing the input stream 4$input = fopen('php://stdin', 'r'); 5 6// initializing error stream 7$err = fopen('php://stderr', 'w'); 8 9// unlike the previous cases, here is tested for the end of the file 10// because the input is not coming from keyboard 11while(!feof($input)) { 12 // the value is trimmed to remove line terminators 13 $line = trim(fgets($input, 1024)); 14 15 // test email address 16 if(filter_var($line, FILTER_VALIDATE_EMAIL)) { 17 // direct output, equivalent to php://stdout stream 18 echo $line . PHP_EOL; 19 } else { 20 // invalid addresses are redirected to the php://stderr stream 21 // to be intercepted later 22 fputs($err, $line . PHP_EOL); 23 } 24} 25 26// close input stream 27fclose($input); 28 29// close error stream 30fclose($err);
For testing I’ll simulate the output of email addresses with the cat command:
1cat email.txt |./emailTest.php >valid.txt 2>invalid.txt
Now the files valid.txt and invalid.txt from the current directory contain the proper values.
Processing like this is very useful for complex operations. Basically is an alternative to Shell Scripting (linux) or Batch Scripting (windows), which are not as flexible.
Script arguments
Often is useful to send direct arguments to a script to have, for instance, a different functionality.
Let’s change the previous scenario to receive the name of the file that contains the email address, as a script argument.
The script arguments are automatically stored in the $argv variable. Notice the first element of the array ($argv[0]) is the name of the script!
The modified example is as follows:
1#!/usr/bin/php 2<?php 3 4// the count stars at 1 to eliminate the name of the script 5for ($i = 1; $i < count($argv); $i++) { 6 // initializing the input stream 7 $input = fopen($argv[$i], 'r'); 8 9 // initializing error stream 10 $err = fopen('php://stderr', 'w'); 11 12 if(!$input) { 13 continue; 14 } 15 16 // unlike the previous cases, here is tested for the end of the file 17 // because the input is not coming from keyboard 18 while(!feof($input)) { 19 // the value is trimmed to remove line terminators 20 $line = trim(fgets($input, 1024)); 21 22 // test email address 23 if(filter_var($line, FILTER_VALIDATE_EMAIL)) { 24 // direct output, equivalent to php://stdout stream 25 echo $line . PHP_EOL; 26 } else { 27 // invalid addresses are redirected to the php://stderr stream 28 // to be intercepted later 29 fputs($err, $line . PHP_EOL); 30 } 31 } 32 33 // close input stream 34 fclose($input); 35 36 // close error stream 37 fclose($err); 38}
Now just run the script with arguments:
1$./argTest.php email.txt >valid.txt 2>invalid.txt