25 Years of PHP

DevBreak

Château du Vivier

June 13, 2019

http://talks.php.net/devbreak

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>

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

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

Version Support

Active Support Regular releases and security fixes
Security Fixes Only security fixes
End of Life No longer supported

PHP 7.4

Typed Properties

class User {
    public int $id;
    public string $name;
 
    public function __construct(int $id, string $name) {
        $this->id = $id;
        $this->name = $name;
    }
}

Arrow Functions

$cb = function ($x) use ($y) {
          return $x + $y;
      };

$cb = fn($x) => $x + $y;

__serialize/__unserialize

class Test {
    public $prop;
    public function __serialize() {
        return ['prop' => $this->prop];
    }
    public function __unserialize(array $data) {
        $this->prop = $data['prop'];
    }
}

Null Coalescing Assignment Operator

$this->config['value']   = $this->config['value'] ?? 'default_value';
$this->config['value'] ??= 'default_value';

Weak References

$std = new stdClass;
$wr = WeakReference::create($std);

Opcache Preloading

  • Loads userspace code at server startup as if it was part of core PHP
  • Trades some flexibility for performance
  • Inspired by the “Class Data Sharing” feature in Java's Hotspot VM

Without Opcache Preloading

class A {
    function __construct() {
        echo "A";
    }
}
spl_autoload_register('__load');
function __load($c) {
    echo "Autoloader called for $c\n";
    require "/home/rasmus/".strtolower($c).".php";
}

new A;
$ php script.php 
Autoloader called for A
A

With Opcache Preloading

function preload($filename) {
    if (!opcache_compile_file($filename)) {
        trigger_error("Preloading Failed", E_USER_ERROR);
    }
}

preload("/home/rasmus/a.php");
$ php -d opcache.preload=preload.php script.php 
A

FFI - Foreign Function Interface

// create FFI object, loading libc and exporting function printf()
$ffi = FFI::cdef(
    "int printf(const char *format, ...);",
    "libc.so.6");
// call C printf()
$ffi->printf("Hello %s!\n", "world");
<?php
    $ffi = FFI::load("php_gifenc.h");

    $w = 240; $h = 180;
    $cols = $ffi->new("uint8_t[12]");
    /* 4 colours: 000000, FF0000, 00FF00, 0000FF */
    $cols[3] = 0xFF; $cols[7] = 0xFF; $cols[11] = 0xFF;

    $gif = $ffi->ge_new_gif("test.gif", $w, $h, $cols, 2, 0);

    for($i = 0; $i < 16; $i++) {
        for ($j = 0; $j < $w*$h; $j++) {
            $gif->frame[$j] = ($i*6 + $j) / 12 % 8;
        }
        echo "Add frame $i\n";
        $ffi->ge_add_frame($gif, 5);
    }
    $ffi->ge_close_gif($gif);
#define FFI_SCOPE "gifenc"
#define FFI_LIB "libgifenc.so"

typedef struct ge_GIF {
    uint16_t w, h;
    int depth;
    int fd;
    int offset;
    int nframes;
    uint8_t *frame, *back;
    uint32_t partial;
    uint8_t buffer[0xFF];
} ge_GIF;

ge_GIF *ge_new_gif(
    const char *fname, uint16_t width, uint16_t height,
    uint8_t *palette, int depth, int loop
);
void ge_add_frame(ge_GIF *gif, uint16_t delay);
void ge_close_gif(ge_GIF* gif);

Work on things that matter (to you)

Thank You

http://talks.php.net/devbreak
https://github.com/phan/phan
https://github.com/adsr/phpspy
http://php.net/migration73
https://bugs.php.net



Report Bugs

Useful bug reports, please!