The 5.5 release comes bundled with a number of new features.
Generators
The general foreach statement in PHP looks like the following:
foreach($collection as $item) {
// process item }
This works for arrays and iterators containing efficiently small data sets since all data is stored in memory. For larger data sets, we need another solution.
A generator is a special function used to augment the iteration behavior of a loop statement. In basic terms, generators are similar to functions that return an array or sequence of values; instead of returning all values at once, generators return values one at a time, thereby utilizing less memory and processing time. This is a very powerful language feature that has been present in other languages, such as Python, for quite some time. And now it’s being added to PHP.
Generators are very closely linked to iterators. Iterators are a language construct available in PHP via the SPL library and the Iterator interface.
Iterators
Added in 5.0, the Iterator interface can be used to create custom external iterators. A class is considered iterable if it extends the following interface:
Embedding an instance of this class in a foreach() will treat it as if it were a collection, so long as the valid() and next() calls continue producing valid results.
The latest versions of PHP5+ take advantage of this and provide a variety of canned iterators to choose from via the SPL library. For more information on SPL iterators, please visit http://php.net/manual/en/spl.iterators.php.
For more information on iterators in general, visit http://php. net/manual/en/class.iterator.php.
Generators
Generators provide yet another alternative when creating simple iterators without having to implement any interfaces.
Similar to iterators, generators allow developers to write code that leverages foreach()to traverse a set of data in both a memory and processing-efficient manner. Instead of traversing elements all at once, generator functions take advantage of the yield keyword to produce results as many times as needed to provide the value set being iterated over. The presence of yield turns any function into a generator. Behind the scenes, PHP will save the state of the generator when it yields a value so that it can be “woken up” next time a value is required.
When a generator function is called, an instance of the Generator class is returned. Behind the scenes, this class implements the Iterator interface previously discussed and adds 3 methods:
Generator implements Iterator {
public mixed send ( mixed $value )
public mixed throw ( Exception $exception ) public void __wakeup ( void )
}
These methods allow generators internally to save its state and resume where it left off next time it’s called.
The PHP range($start, $end, [, number $step = 1]) function is used to generate an array of values with every element in it from start to end parameters inclusively, separated by the step value.
foreach (range(0, 100000) as $number) {
echo $number; }
This statement will create an array of 100001 elements (including 0), loop over all of them and print each one. Understandably, the performance of the range function is degraded as the end value becomes bigger. Generators can be used to implement range() much more effectively. Let’s call it xrange($start, $end, [, number $step = 1]).
function xrange($start, $limit, $step = 1) {
if ($start < $limit) {
for ($i = $start; $i <= $limit; $i += $step) {
yield $i; }
} else {
for ($i = $start; $i >= $limit; $i += $step) {
yield $i; }
} }
Generator functions return a Generator instance, which we can place inside of a foreach statement and iterate over a range of elements without ever needing additional memory.
foreach (xrange(0, 100000) as $number) {
echo $number; }
Let’s look at simplifying another task done on a daily basis where generators can play a significant role, file I/O:
Let’s look at simplifying another task done on a daily basis where generators can play a significant role, file I/O:
function readLinesFrom($filename) {
$fh = fopen($filename, ‘r’);
if (!$fh)
throw new Exception(‘Error opening file ’.
$filename);
while (($line = fgets($fh)) !== false)
yield $line; }
fclose($fh); }
This function can be used to read lines from a text file. The important statement in this code is the loop. As lines are read, the generator function yields each line one at a time, starting where it left off without creating any additional memory allocations. The calling code looks like the following:
foreach (readLinesFrom(‘myFile.txt’) as $line) {
//do something with $line }
Another feature of generators is the ability to inject or send a value to the generator, which could be useful for stopping the generation process. Consider a simplified version of the xrange() function above:
function xrange($start, $limit, $step = 1) {
if ($start < $limit) {
for ($i = $start; $i <= $limit; $i += $step) {
$res = (yield $i);
if($res == ‘stop’) {
return;//exit the function }
} }
}
$gen = xrange(1, 10);
foreach($gen as $v)
{
if($v == 5) {
// stop generating more numbers
$gen->send(‘stop’); }
echo “{$v}\n”; }
The result of the current yield expression can be captured and evaluated. By calling the send function in the client code, a value can be injected into the generator and halt the process.
More information on generators can be found at http://php.net/ manual/en/language.generators.overview.php.
Exception Handling and the Finally Keyword
Exception handling had been added to PHP in version 5. Code can be surrounded in a try-catch block to facilitate the catching of potential errors. Classic uses of exception blocks are file I/O and network I/O functions. Each try is accompanied by at least one catch block and multiple catch blocks can be used to handle different types of exceptions.
PHP 5.5 adds support for the finally keyword. Similar to Java, the finally block is appended to try-catch blocks and it is guaranteed to run regardless of whether an exception occurs within the try block or before normal execution resumes. Here is the general syntax:
$handle= fopen(‘myFile.txt’, ‘w+’); try {
// Open a directory and run some code
fopen($handle, ‘Some Text’); }
catch (Exception $e) {
echo ‘Caught exception: ‘, $e->getMessage(), “\n”; }
finally { fclose($handle);
echo “Close directory”;
}
The finally block is used typically to free up resources that were taken up before or during the execution of the try statement. Adding support for finally is another step at enhancing PHP’s error handling mechanism to compete with other programming languages, and also to improve the quality of error handling code. Unlike Java, however, PHP does not establish a distinction between checked and unchecked exceptions – essentially all exceptions are runtime exceptions.
Security
PHP 5.5 has a new API that facilitates the generation of password hashes using the same underlying library as crypt(), which is a one-way password hashing function available in PHP since version 4. Password hashing is very useful when needing to store and validate passwords in a database for authentication purposes.
The new password_hash() function acts as a wrapper to crypt() making it very convenient to create and manage passwords in a strong and secure manner. Streamlining this API will make it easier for developers to start adopting it over the much older and weaker md5() and sha1() functions, which are still heavily used today.
Since it is built-in to the PHP core, this extension has no dependencies on external libraries, and does not require special php.ini directives to use.
The API consists of the following functions:
FUNCTION NAME |
DESCRIPTION |
password_get_info |
Returns information about the given hash as an array: salt, cost and algorithm used |
password_hash |
Creates a password hash |
password_needs_rehash |
Checks if the given hash matches the options provided |
password_verify |
Verifies password matches a given hash |
Here is some sample code:
// generate new hash
$password = ‘MyP@ssword!’;
$new_hash = password_hash($password, PASSWORD_DEFAULT); print “Generated New Password Hash: “ + $new_hash + “\n”;
// get info about this hash
$info = password_get_info($new_hash); v a r_ d u m p ($ i n f o);
// verify hash
$isVerified = password_verify($password, $new_hash); if($isVerified) {
}
print “Password is valid!\n”;
// check for rehash
$needs_rehash = password_needs_rehash($new_hash, PASSWORD_DEFAULT);
if(!$needs_rehash) {
print “Password does not need rehash as it is valid”;
}
The new hashing API supports a few options when generating password hashes: salt, the algorithm, and a cost.
OPTION NAME |
DESCRIPTION |
salt |
This is an optional string to base the hashing algorithm on. The new hashing API does not require or recommend the use of a custom salt. |
algo |
The default algorithm built in to PHP 5.5 is the Bcrypt algorithm (also called Blowfish), but you are free to use others supported by the crypt() function such as Blowfish or Standard DES. |
cost |
Associated with an encryption algorithm is a cost value that represents the number of iterations used when generating a hash. In the password hash API, a default baseline value of 10 (2^10 = 1024 iterations) is used, but you can increment this on better hardware. Cost values range from 04 – 31. |
More information on password hashing, visit http://php.net/ manual/en/book.password.php.
{{ parent.title || parent.header.title}}
{{ parent.tldr }}
{{ parent.linkDescription }}
{{ parent.urlSource.name }}