Coding and Dreaming

NZ PHP Conf

Wellington

Aug 28, 2014

http://talks.php.net/nz14

Rasmus Lerdorf
@rasmus

1993


#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

#define ishex(x) (((x) >= '0' && (x) <= '9') || ((x) >= 'a' && \
                   (x) <= 'f') || ((x) >= 'A' && (x) <= 'F'))

int htoi(char *s) {
	int     value;
	char    c;

	c = s[0];
	if(isupper(c)) c = tolower(c);
	value=(c >= '0' && c <= '9' ? c - '0' : c - 'a' + 10) * 16;

	c = s[1];
	if(isupper(c)) c = tolower(c);
	value += c >= '0' && c <= '9' ? c - '0' : c - 'a' + 10;

	return(value);
}

void main(int argc, char *argv[]) {
	char *params, *data, *dest, *s, *tmp;
	char *name, *age;

	puts("Content-type: text/html\r\n");
	puts("<HTML><HEAD><TITLE>Form Example</TITLE></HEAD>");
	puts("<BODY><H1>My Example Form</H1>");
	puts("<FORM action=\"form.cgi\" method=\"GET\">");
	puts("Name: <INPUT type=\"text\" name=\"name\">");
	puts("Age: <INPUT type=\"text\" name=\"age\">");
	puts("<BR><INPUT type=\"submit\">");
	puts("</FORM>");

	data = getenv("QUERY_STRING");
	if(data && *data) {
		params = data; dest = data;
    	while(*data) {
			if(*data=='+') *dest=' ';
			else if(*data == '%' && ishex(*(data+1))&&ishex(*(data+2))) {
				*dest = (char) htoi(data + 1);
				data+=2;
			} else *dest = *data;
			data++;
			dest++;
		}
		*dest = '\0';
		s = strtok(params,"&");
		do {
			tmp = strchr(s,'=');
			if(tmp) {
				*tmp = '\0';
				if(!strcmp(s,"name")) name = tmp+1;
				else if(!strcmp(s,"age")) age = tmp+1;
			}
		} while(s=strtok(NULL,"&"));

		printf("Hi %s, you are %s years old\n",name,age);
	}
	puts("</BODY></HTML>");
}

1993


use CGI qw(:standard);
print header;
print start_html('Form Example'),
    h1('My Example Form'),
    start_form,
    "Name: ", textfield('name'),
    p,
    "Age: ", textfield('age'),
    p,
    submit,
    end_form;
if(param()) {
    print "Hi ",em(param('name')),
        "You are ",em(param('age')),
        " years old";
}
print end_html;

1994


<html><head><title>Form Example</title></head>
<body><h1>My Example Form</h1>
<form action="form.phtml" method="POST">
Name: <input type="text" name="name">
Age: <input type="text" name="age">
<br><input type="submit">
</form>
<?if($name):?>
Hi <?echo $name?>, you are <?echo $age?> years old
<?endif?>
</body></html>

Focus on the Ecosystem

  • LAMP wasn't an accident
  • Robustness, Performance and Security
  • shared hosting ISPs

Scale

  • Scaling up is expected
  • Scaling down is surprisingly hard
  • Doing both is rocket science

Performance

  • mod_php
  • shared-nothing perfect sandbox model

Robustness

  • SQL LIMIT clause
  • Promote Prefork shared-nothing model

Security

  • max_execution_time
  • memory_limit
  • safe mode

What was he thinking?

  • Case insensitive function names?
  • Naming inconsistencies?
  • What's with the $ signs?
  • Globals?
  • register_globals?
  • magic_quotes?

OMGWTFBBQ?

array_search($needle, $haystack);
strstr($haystack, $needle);
in_array($needle, $haystack);
substr_count($haystack, $needle);
array_key_exists($needle, $haystack);
strchr($haystack, $needle);

2014

PHP 5.5


Performance Improvements

  • Nested calls
  • Call stack pre-allocated by compiler
  • Bundled opcode cache

✔ Generators

function xrange($start, $end) {
    for ($i = $start; $i <= $end; $i ++) {
        yield $i;
    }
}
foreach (xrange(0, 5) as $i) {
    echo $i, "\n";
}

✔ Coroutines

function logger($fileName) {
    $fileHandle = fopen($fileName, 'a');
    while (true) {
        fwrite($fileHandle, yield . "\n");
    }
}

$logger = logger(__DIR__ . '/log');
$logger->send('Foo');
$logger->send('Bar');

For an advanced explanation of coroutines, read this article by Nikita Popov

Cooperative multitasking using coroutines

✔ finally

$db = mysqli_connect();
try {
   call_some_function($db);
} finally {
   mysqli_close($db);
}

✔ list() in foreach

$names = [ ['John','Smith'], ['Fred','Johnson'] ];
foreach($names as list($first,$last)) { 
    echo $first,$last; 
}

✔ Const array/string Dereferencing

echo array(1, 2, 3)[0]; //output 1
echo "foobar"[3]; //output b
echo [1,3,4][2]; //output 4

✔ empty() support for functions/expressions

✔ curl upload functionality rewritten

✔ Simplified password hashing API

// Hash
$hash = password_hash("super secret",PASSWORD_BCRYPT);

// To validate $pwd against the stored hash
if (password_verify($pwd, $hash)) {
    echo 'Password is valid!';
} else {
    echo 'Invalid password.';
}
php.net/migration55

PHP 5.6


http://php.net/spec

✔ Variadic functions

class MySQL implements DB {
    public function query($query, ...$params) {
        $stmt = $this->pdo->prepare($query);
        $stmt->execute($params);
        return $stmt;
    }
}

$q = 'SELECT * FROM users WHERE id = ?';
$user = $db->query($q, $userID)->fetch();

✔ Argument Unpacking

// A better call_user_func_args
$args1 = [1, 2, 3];
$args2 = [4, 5, 6];
test(...$args1, ...$args2); // [1, 2, 3, 4, 5, 6]
test(1, 2, 3, ...$args2);   // [1, 2, 3, 4, 5, 6]
test(...$args1, 4, 5, 6);   // Fatal error: Cannot use positional argument after argument unpacking

✔ Constant scalar expressions

class Foo {
    const FOO = 1 + 1;
    const BAR = 1 << 1;
    const GREETING = "HELLO";
    const BAZ = self::GREETING." WORLD!"
}

✔ Add right-associative power operator **

echo 2 ** 3 ** 2; // 512 (not 64)
echo -3 ** 2; // -9 (not 9)
echo 1 - 3 ** 2; // -8
echo ~3 ** 2; // -10 (not 16)

✔ Internal operator overloading for internal features like GMP

echo 2**512;
echo "\n";
$n = gmp_init(2);
echo $n**512;
1.3407807929943E+154
13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084096
		

✔ use function and use const namespace imports

include 'template.inc';
include 'db.inc';
use function template\header, template\footer, db\query;

header('My Page');
query('select * from stuff');
footer();

✔ default_charset ini now applies to internal funcs

✔ SSL Peer verification by default

✔ openssl certificate fingerprints

✔ SAN x509 ext matching when verifying host names

✔ automatic DoS prevention of TLS renegotiation attacks

✔ and many more openssl-related options

✔ Asynchronous PostgreSQL database connections

✔ Non-blocking PostgreSQL queries

✔ New phpdbg SAPI

✔ Support for > 2GB file uploads

✔ The php://input stream is now re-usable

✔ Added hash_equals() for timing attack safe string comparison

✔ Added gost-crypto (CryptoPro S-box) hash algorithm

✔ FPM workers can now change their apparmor profile

✔ OCI8 Improvements

php.net/migration56

PHP 7


✔ phpng engine improvements

  • 10-25% performance gain on most realworld applications
  • lower memory usage
  • Cleans up some things for a future JIT

✔ Abstract Syntax Tree

✔ 64-bit integer support on Windows

✔ Catchable "call to member function of non-object"

✔ Various cleanups (remove old ASP/script tags and more)

✔ Null Coalesce Operator

$a = NULL;
$b = 1;
$c = 2;

echo $a ?? $b; // 1
echo $c ?? $b; // 2
echo $a ?? $b ?? $c; // 1
echo $a ?? $x ?? $c; // 2

✔ Uniform variable syntax

// support missing combinations of operations
$foo()['bar']()
[$obj1, $obj2][0]->prop
getStr(){0}
 
// support nested ::
$foo['bar']::$baz
$foo::$bar::$baz
$foo->bar()::baz()
 
// support nested ()
foo()()
$foo->bar()()
Foo::bar()()
$foo()()
 
// support operations on arbitrary (...) expressions
(...)['foo']
(...)->foo
(...)->foo()
(...)::$foo
(...)::foo()
(...)()
 
// two more practical examples for the last point
(function() { ... })()
($obj->closure)()
 
// support all operations on dereferencable scalars
// (not very useful)
"string"->toLower()
[$obj, 'method']()
'Foo'::$bar

Still early. More things will likely be added

First RC scheduled for June 2015

Work on things that matter (to you)

Sense of Purpose

The Purpose Economy: How Your Desire for Impact, Personal Growth and Community Is Changing the World

by Aaron Hurst

We are running out of things that can be solved in isolation with our keyboards