25 Years of PHP

HHS Programming Club

Sunnyvale

Apr.5, 2019

http://talks.php.net/hhs

Rasmus Lerdorf
@rasmus

1980s

1990s

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-1995

<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>

PHP Announcement June 8, 1995

Posted to comp.infosystems.www.authoring.cgi

Subject: Announce: Personal Home Page Tools (PHP Tools)

Announcing the Personal Home Page Tools (PHP Tools) version 1.0.
These tools are a set of small tight cgi binaries written in C.
They perform a number of functions including:

. Logging accesses to your pages in your own private log files
. Real-time viewing of log information
. Providing a nice interface to this log information
. Displaying last access information right on your pages
. Full daily and total access counters
. Banning access to users based on their domain
. Password protecting pages based on users' domains
. Tracking accesses ** based on users' e-mail addresses **
. Tracking referring URL's - HTTP_REFERER support
. Performing server-side includes without needing server support for it
. Ability to not log accesses from certain domains (ie. your own)
. Easily create and display forms
. Ability to use form information in following documents

Here is what you don't need to use these tools:

. You do not need root access - install in your ~/public_html dir
. You do not need server-side includes enabled in your server
. You do not need access to Perl or Tcl or any other script interpreter
. You do not need access to the httpd log files

The only requirement for these tools to work is that you have
the ability to execute your own cgi programs.  Ask your system
administrator if you are not sure what this means.

The tools also allow you to implement a guestbook or any other
form that needs to write information and display it to users
later in about 2 minutes.

The tools are in the public domain distributed under the GNU
Public License.  Yes, that means they are free!

For a complete demonstration of these tools, point your browser
at: http://www.io.org/~rasmus

--
Rasmus Lerdorf
rasmus@io.org
http://www.io.org/~rasmus

C API for the Web

void Cos(void) {
    Stack *s;
    char temp[64];

    s = Pop();
    if(!s) {
        Error("Stack error in cos");
        return;
    }
    sprintf(temp,"%f",cos(s->douval));
    Push(temp,DNUMBER);
}

And you could then use it like this:

<html><head><title>Cos Example</title></head>
<body><h1>Cos Example</h1>
<?echo Cos($input)>
</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

PHP 7.3

Flexible Heredoc

class foo {
    public $bar = <<<EOT
    bar
    EOT;
}

Continue in Switch

while ($foo) {
    switch ($bar) {
        case "baz":
            continue;
    }
}
Warning: "continue" targeting switch is equivalent to "break".
         Did you mean to use "continue 2"?

List References

$array = [1, 2];
list($a, &$b) = $array;
// or
[$a, &$b] = $array;

Trailing comma allowed in function calls

$newArray = array_merge(
    $arrayOne,
    $arrayTwo,
    ['foo', 'bar'],
);

# Parse error
function bar($a, $b,) { }

# Parse error
foo(,);

# Parse error
foo('function', 'bar',,);

# Also parse error
foo(, 'function', 'bar');

New Monotonic Timer function

php > print_r(hrtime());
Array
(
    [0] => 2320165    // seconds
    [1] => 979969517  // nanoseconds
)
php > print_r(hrtime(true));
2320183081647424

New fpm_get_status() function

print_r(fpm_get_status());
Array (
    [pool] => www
    [process-manager] => static
    [start-time] => 1536934549
    [start-since] => 26
    [accepted-conn] => 20039
    [listen-queue] => 0
    [max-listen-queue] => 0
    [listen-queue-len] => 0
    [idle-processes] => 0
    [active-processes] => 47
    [total-processes] => 47
    [max-active-processes] => 514
    [max-children-reached] => 0
    [slow-requests] => 0
    [procs] => Array (
            [0] => Array (
                    [pid] => 10819
                    [state] => Running
                    [start-time] => 1536934549
                    [start-since] => 26
                    [requests] => 2001
                    [request-duration] => 8108
                    [request-method] => GET
                    [request-uri] => /index.php
                    [query-string] => p=1
                    [request-length] => 0
                    [user] => -
                    [script] => /var/www/wordpress/index.php
                    [last-request-cpu] => 0
                    [last-request-memory] => 0
                )
            ...

is_countable()

if (is_array($foo) || $foo instanceof Countable) {
    // $foo is countable
}

if (is_countable($foo)) {
    // $foo is countable
}

array_key_first()/array_key_last()

$a = ['abc'=>'First', 'def'=>'Second', 'ghi'=>'Third'];
echo array_key_first($a);
// abc
echo array_key_last($a);
// ghi

More DCE and SCCP optimizations

Other changes

  • Upgraded from PCRE to PCRE2
  • getallheaders() now available in php-fpm
  • full case-mapping for mbstring
  • preg_quote() now also escapes '#'
  • new gmp functions: gmp_binomial, gmp_lcm, gmp_perfect_power, gmp_kronecker
  • new JsonException
  • default ftp transfer mode is now binary

Things that may break your code

  • PCRE2 differences (should be rare)
  • ODBCRouter and Birdstep support have been removed
  • Various deprecations - see UPGRADING

Full details are at:

https://github.com/php/php-src/blob/PHP-7.3/UPGRADING

And for extension authors:

https://github.com/php/php-src/blob/PHP-7.3/UPGRADING.INTERNALS

Dead Code Elimination (DCE)

Escape Analysis

Sparse Conditional Constant Propagation

php -d opcache.optimization_level=-1 -d opcache.opt_debug_level=0x20000 script
function fn() {
    $a = 1;
    return 0;
}

PHP 7.1

fn: (lines=2, args=0, vars=1, tmps=0)
L0:   ASSIGN CV0($a) int(1)
L1:   RETURN int(0)

PHP 7.2/7.3

fn: (lines=1, args=0, vars=0, tmps=0)
L0:   RETURN int(0)
function foo(string $s1, string $s2, string $s3, string $s4) {
    $x = ($s1 . $s2) . ($s3 . $s4);
    $x = 0;
    return $x;
}
PHP 7.1                                   PHP 7.2/7.3
foo: (lines=10, args=4, vars=5, tmps=3)   foo: (lines=5, args=4, vars=4, tmps=0)
L0:   CV0($s1) = RECV 1                   L0:   CV0($s1) = RECV 1
L1:   CV1($s2) = RECV 2                   L1:   CV1($s2) = RECV 2
L2:   CV2($s3) = RECV 3                   L2:   CV2($s3) = RECV 3
L3:   CV3($s4) = RECV 4                   L3:   CV3($s4) = RECV 4
L4:   T6 = CONCAT CV0($s1) CV1($s2)       L4:   RETURN int(0)
L5:   T7 = CONCAT CV2($s3) CV3($s4)
L6:   T5 = CONCAT T6 T7
L7:   ASSIGN CV4($x) T5
L8:   ASSIGN CV4($x) int(0)
L9:   RETURN CV4($x)

Try to trick it

function foo($a) {
    $b = $a += 3;
    return $a;
}

PHP 7.2/7.3

foo: (lines=3, args=1, vars=1, tmps=1)
L0:   CV0($a) = RECV 1
L1:   ASSIGN_ADD CV0($a) int(3)
L2:   RETURN CV0($a)

But...

function foo(int $x, int $y) {
    $a = [$x];
    $a[1] = $y;
    $a = $y;
    return $a;
}
PHP 7.2                                    PHP 7.3
foo: (lines=7, args=2, vars=3, tmps=1)     foo: (lines=4, args=2, vars=3, tmps=0)
L0:   CV0($x) = RECV 1                     L0:     CV0($x) = RECV 1
L1:   CV1($y) = RECV 2                     L1:     CV1($y) = RECV 2
L2:   CV2($a) = INIT_ARRAY 1 CV0($x) NEXT  L2:     CV2($a) = QM_ASSIGN CV1($y)
L3:   ASSIGN_DIM CV2($a) int(1)            L3:     RETURN CV2($a)
L4:   OP_DATA CV1($y)
L5:   ASSIGN CV2($a) CV1($y)
L6:   RETURN CV2($a)
class A { }
function foo(int $x) {
    $a = new A;
    $a->foo = $x;
    return $x;
}

PHP 7.3

foo: (lines=2, args=1, vars=1, tmps=0)
L0:   CV0($x) = RECV 1
L1:   RETURN CV0($x)
class A {
    function __destruct() {}
}
function foo(int $x) {
    $a = new A;
    $a->foo = $x;
    return $x;
}

PHP 7.3

foo: (lines=7, args=1, vars=2, tmps=1)
L0:   CV0($x) = RECV 1
L1:   V2 = NEW 0 string("A")
L2:   DO_FCALL
L3:   CV1($a) = QM_ASSIGN V2
L4:   ASSIGN_OBJ CV1($a) string("foo")
L5:   OP_DATA CV0($x)
L6:   RETURN CV0($x)
function foo(int $x) {
    if ($x) {
        $a = [0,1];
    } else {
        $a = [0,2];
    }
    return $a[0];
}

PHP 7.3

foo: (lines=2, args=1, vars=1, tmps=0)
L0:   CV0($x) = RECV 1
L1:   RETURN int(0)
function foo() {
    $o = new stdClass();
    $o->foo = 0;
    $i = 1;
    $c = $i < 2;
    if ($c) {
        $k = 2 * $i;
        $o->foo = $i;
        echo $o->foo;
    }
    $o->foo += 2;
    $o->foo++;
    return $o->foo;
}

PHP 7.3

foo: (lines=2, args=0, vars=0, tmps=0)
L0:   ECHO int(1)
L1:   RETURN int(4)

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

Thank You




http://php.net
http://talks.php.net/hhs