Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Stupid PHP Tricks

John Bafford
November 14, 2014

Stupid PHP Tricks

PHP is an incredibly flexible language, with an interesting array of built-in functionality. In this talk, I’ll show you some of my favorite and hidden features in PHP. Learn how to abuse output buffering, the [] operator, and three ways to limit how long a function can execute.

Presented on November 14, 2014 at php[world].

John Bafford

November 14, 2014
Tweet

More Decks by John Bafford

Other Decks in Technology

Transcript

  1. © 2014 John Bafford php[world] 2014 — 11/14/2014
    “Stupid PHP Tricks”
    John Bafford!
    http://bafford.com — @jbafford — [email protected]
    !
    The Brick Factory!
    http://thebrickfactory.com — @thebrickfactory — [email protected]
    1

    View Slide

  2. © 2014 John Bafford php[world] 2014 — 11/13/2014
    Who Am I?
    • John Bafford

    Vice President, Programming Services

    The Brick Factory
    • PHP developer since 1999
    • Programmer since 1990
    2

    View Slide

  3. © 2014 John Bafford php[world] 2014 — 11/13/2014
    The Brick Factory
    • Full Service Web Development Shop
    • Farragut North, DC
    • We do lots of Drupal sites
    3

    View Slide

  4. © 2014 John Bafford php[world] 2014 — 11/13/2014
    Output Buffers
    4

    View Slide

  5. © 2014 John Bafford php[world] 2014 — 11/13/2014
    Pop Quiz
    function a(){ echo 'Hello'; echo 'World'; }
    function b(){ echo 'Hello', 'World'; }
    function c(){ echo 'Hello' . 'World'; }
    5

    View Slide

  6. function a(){ echo 'Hello'; echo 'World'; }
    !
    line # * op fetch ext return operands!
    ---------------------------------------------------------------------------------!
    3 0 > ECHO 'Hello'!
    1 ECHO 'World'!
    2 > RETURN null!
    !
    !
    !
    function b(){ echo 'Hello', 'World'; }
    !
    line # * op fetch ext return operands!
    ---------------------------------------------------------------------------------!
    4 0 > ECHO 'Hello'!
    1 ECHO 'World'!
    2 > RETURN null!
    !
    !
    !
    function c(){ echo 'Hello' . 'World'; }
    !
    line # * op fetch ext return operands!
    ---------------------------------------------------------------------------------!
    5 0 > CONCAT ~0 'Hello', 'World'!
    1 ECHO ~0!
    2 > RETURN null!

    View Slide

  7. function a(){ echo 'Hello'; echo 'World'; }
    !
    line # * op fetch ext return operands!
    ---------------------------------------------------------------------------------!
    3 0 > ECHO 'Hello'!
    1 ECHO 'World'!
    2 > RETURN null!
    !
    !
    !
    function b(){ echo 'Hello', 'World'; }
    !
    line # * op fetch ext return operands!
    ---------------------------------------------------------------------------------!
    4 0 > ECHO 'Hello'!
    1 ECHO 'World'!
    2 > RETURN null!
    !
    !
    !
    function c(){ echo 'Hello' . 'World'; }
    !
    line # * op fetch ext return operands!
    ---------------------------------------------------------------------------------!
    5 0 > CONCAT ~0 'Hello', 'World'!
    1 ECHO ~0!
    2 > RETURN null!

    View Slide

  8. function a(){ echo 'Hello'; echo 'World'; }
    function b(){ echo 'Hello', 'World'; }
    function c(){ echo 'Hello' . 'World'; }
    function obwrap($fn)
    {
    ob_start(function($s) { return $s . $s; }, 1);
    $fn();
    ob_end_clean();
    }
    $ob = false;
    for($x = 1; $x < $argc; $x++) {
    $fn = $argv[$x];
    if($fn == ‘--ob') {
    $ob = true;
    continue;
    }
    echo "$fn:\n";
    if($ob)
    obwrap($fn);
    else
    $fn();
    echo "\n\n";
    }
    php st-ob.php a b c!
    a:!
    HelloWorld!
    !
    b:!
    HelloWorld!
    !
    c:!
    HelloWorld!

    View Slide

  9. function a(){ echo 'Hello'; echo 'World'; }
    function b(){ echo 'Hello', 'World'; }
    function c(){ echo 'Hello' . 'World'; }
    function obwrap($fn)
    {
    ob_start(function($s) { return $s . $s; }, 1);
    $fn();
    ob_end_clean();
    }
    $ob = false;
    for($x = 1; $x < $argc; $x++) {
    $fn = $argv[$x];
    if($fn == ‘--ob') {
    $ob = true;
    continue;
    }
    echo "$fn:\n";
    if($ob)
    obwrap($fn);
    else
    $fn();
    echo "\n\n";
    }
    php st-ob.php a b c!
    a:!
    HelloWorld!
    !
    b:!
    HelloWorld!
    !
    c:!
    HelloWorld!
    php st-ob.php --ob a b c!
    a:!
    HelloHelloWorldWorld!
    !
    b:!
    HelloHelloWorldWorld!
    !
    c:!
    HelloWorldHelloWorld!

    View Slide

  10. php st-ob.php --ob a b c!
    a:!
    HelloHelloWorldWorld!
    !
    b:!
    HelloHelloWorldWorld!
    !
    c:!
    HelloWorldHelloWorld!

    View Slide

  11. chunk_size

    If the optional parameter chunk_size is passed, the buffer will be flushed after any output call
    which causes the buffer's length to equal or exceed chunk_size. The default value 0 means that
    the output function will only be called when the output buffer is closed.

    !
    Prior to PHP 5.4.0, the value 1 was a special case value that set the chunk size to 4096 bytes.

    bool ob_start (







    [ callable $output_callback = NULL







    [, int $chunk_size = 0







    [, int $flags = PHP_OUTPUT_HANDLER_STDFLAGS






    ]]] )

    View Slide

  12. function a(){ echo 'Hello'; echo 'World'; }
    function b(){ echo 'Hello', 'World'; }
    function c(){ echo 'Hello' . 'World'; }
    function obwrap($fn)
    {
    ob_start(function($s) { return $s . $s; }, 1);
    $fn();
    ob_end_clean();
    }
    $ob = false;
    for($x = 1; $x < $argc; $x++) {
    $fn = $argv[$x];
    if($fn == ‘--ob') {
    $ob = true;
    continue;
    }
    echo "$fn:\n";
    if($ob)
    obwrap($fn);
    else
    $fn();
    echo "\n\n";
    }
    php st-ob.php a b c!
    a:!
    HelloWorld!
    !
    b:!
    HelloWorld!
    !
    c:!
    HelloWorld!
    php st-ob.php --ob a b c!
    a:!
    HelloHelloWorldWorld!
    !
    b:!
    HelloHelloWorldWorld!
    !
    c:!
    HelloWorldHelloWorld!

    View Slide

  13. © 2014 John Bafford php[world] 2014 — 11/13/2014
    http_build_query
    13

    View Slide

  14. Generates a URL-encoded query string from the associative (or indexed) array provided.
    string http_build_query (


    mixed $query_data


    [, string $numeric_prefix


    [, string $arg_separator


    [, int $enc_type = PHP_QUERY_RFC1738

    ]]] )

    View Slide

  15. © 2014 John Bafford php[world] 2014 — 11/13/2014
    Please Don’t Write This
    $url = "https://your.favorite.api/favoritizer/
    json?api_key=%s&api_secret=
    %s&param_one=value&param_two=%s&%message=%s";
    $encoded = urlencode($some_message)
    $url = sprintf($url, $api_key, $api_secret,
    'value', $param_two, $encoded);
    15

    View Slide

  16. © 2014 John Bafford php[world] 2014 — 11/13/2014
    Write This Instead
    $url = "https://your.favorite.api/favoritizer/
    json?" . http_build_query([
    'api_key' => $api_key,
    'api_secret' => $api_secret,
    'param_one' => 'value',
    'param_two' => $param_two,
    'message' => $some_message,
    ]);
    16

    View Slide

  17. © 2014 John Bafford php[world] 2014 — 11/13/2014
    []
    17

    View Slide

  18. $array = [];
    $array[] = 'foo';
    $array[] = 'bar';
    print_r($array);
    /*
    Array
    (
    [0] => foo
    [1] => bar
    )
    */

    View Slide

  19. $array = [];
    $array[] = 'foo';
    $array[] = 'bar';
    print_r($array);
    /*
    Array
    (
    [0] => foo
    [1] => bar
    )
    */
    !
    !
    $x = $array[];
    /*
    Fatal error: Cannot use [] for reading in …/phpworld/StupidPHPTricks/array.php on line
    124
    */

    View Slide

  20. $array = [];
    $array[] = 'foo';
    $array[] = 'bar';
    print_r($array);
    /*
    Array
    (
    [0] => foo
    [1] => bar
    )
    */
    !
    !
    $foo = 'foo';
    $bar = &$foo;
    var_dump($foo, $bar);
    /*
    string(3) "foo"
    string(3) "foo"
    */
    !
    !
    !
    $bar = 'bar';
    var_dump($foo, $bar);
    /*
    string(3) "bar"
    string(3) "bar"
    */

    View Slide

  21. $array = [];
    $array[] = 'foo';
    $array[] = 'bar';
    print_r($array);
    /*
    Array
    (
    [0] => foo
    [1] => bar
    )
    */
    $array[] = &$foo;
    $foo = 'baz';
    print_r($array);
    /*
    Array
    (
    [0] => foo
    [1] => bar
    [2] => baz
    )
    */

    View Slide

  22. $array = [];
    $array[] = 'foo';
    $array[] = 'bar';
    !
    !
    $baz = ['foo', 'bar'];
    $array[] = &$baz;
    $baz[] = 'baz';
    print_r($array);
    /*
    Array
    (
    [0] => foo
    [1] => bar
    [2] => Array
    (
    [0] => foo
    [1] => bar
    [2] => baz
    )
    )
    */

    View Slide

  23. function setGreek(&$output)
    {
    $output = ['α', 'β', 'ɣ', 'δ'];
    }
    !
    $x = null;
    setGreek($x);
    print_r($x);
    !
    /*
    Array
    (
    [0] => α
    [1] => β
    [2] => ɣ
    [3] => δ
    )
    */

    View Slide

  24. function setGreek(&$output)
    {
    $output = ['α', 'β', 'ɣ', 'δ'];
    }
    !
    !
    setGreek($x);
    print_r($x);
    !
    /*
    Array
    (
    [0] => α
    [1] => β
    [2] => ɣ
    [3] => δ
    )
    */

    View Slide

  25. function setGreek(&$output)
    {
    $output = ['α', 'β', 'ɣ', 'δ'];
    }
    !
    $values = [
    ['1', '2', '3'],
    ['a', 'b', 'c'],
    ];
    !
    setGreek($values[]);
    print_r($values);
    /*
    Array
    (
    [0] => Array
    (
    [0] => 1
    [1] => 2
    [2] => 3
    )
    [1] => Array
    (
    [0] => a
    [1] => b
    [2] => c
    )
    [2] => Array
    (
    [0] => α
    [1] => β
    [2] => ɣ
    [3] => δ
    )
    )
    */

    View Slide

  26. $a = [1, 2, 3];
    $b = &$a[];
    $c = &$a[];
    $a[] = 'a';
    $b = 'b';
    $c = 'c';
    print_r($a);
    /*
    Array
    (
    [0] => 1
    [1] => 2
    [2] => 3
    [3] => b
    [4] => c
    [5] => a
    )
    */

    View Slide

  27. © 2014 John Bafford php[world] 2014 — 11/13/2014
    Practical Application of
    &$arr[]
    27

    View Slide

  28. $xml = simplexml_load_string(file_get_contents('xml.xml'));
    $array = json_decode(json_encode((array) $xml), true);
    $array = array($xml->getName() => $array);

    View Slide

  29. function _parse($xml) {
    $_level = array();
    $_cdata = '';
    $_data = array();
    while($xml->read()) {
    switch($xml->nodeType) {
    case XMLReader::ELEMENT:
    $_cdata = '';
    $name = $xml->name;
    $curLevel = count($_level);
    if($curLevel == 0) //the root
    $_level[] = &$_data[$name][];
    else
    $_level[] = &$_level[$curLevel - 1][$name][];
    //Fall-through and close the tag if it is empty
    if(!$xml->isEmptyElement)
    break;
    case XMLReader::END_ELEMENT:
    if($_cdata != '')
    {
    $curLevel = count($_level) - 1;
    $_level[$curLevel] = $_cdata;
    $_cdata = '';
    }
    array_pop($_level);
    break;
    case XMLReader::TEXT:
    case XMLReader::CDATA:
    $_cdata .= $xml->value;
    break;
    }
    }
    return $_data;
    }

    View Slide



  30. one
    two
    three
    four

    Array(!
    [foo] => Array(!
    [0] => Array(!
    [bar] => Array(!
    [0] => one!
    [1] => two!
    )!
    !
    [baz] => Array(!
    [0] => three!
    [1] => Array(!
    [quux] => Array(!
    [0] => four!
    )!
    )!
    )!
    )!
    )!
    )

    View Slide

  31. © 2014 John Bafford php[world] 2014 — 11/13/2014
    array_combine
    31

    View Slide

  32. Creates an array by using the values from the keys array as keys
    and the values from the values array as the corresponding values.
    array array_combine ( array $keys , array $values )

    View Slide

  33. © 2014 John Bafford php[world] 2014 — 11/13/2014
    array_combine
    $fd = fopen('somefile.csv', 'r');
    $cols = null;
    while(false !== ($row = fgetcsv($fd)))
    {
    if(!$cols)
    $cols = $row;
    else if(count($row) == count($cols))
    {
    $row = array_combine($cols, $row);
    print_r($row);
    }
    }
    33
    A,B,C!
    1,2,3!
    4,5,6
    Array!
    (!
    [A] => 1!
    [B] => 2!
    [C] => 3!
    )!
    Array!
    (!
    [A] => 4!
    [B] => 5!
    [C] => 6!
    )!

    View Slide

  34. © 2014 John Bafford php[world] 2014 — 11/13/2014
    (unset)
    34

    View Slide

  35. © 2014 John Bafford php[world] 2014 — 11/13/2014
    Unset cast
    • Returns null
    • That’s it.
    35

    View Slide

  36. $foo = 'foo';
    $bar = (unset)$foo;
    $foo === 'foo';
    $bar === null;

    View Slide

  37. © 2014 John Bafford php[world] 2014 — 11/13/2014
    WHY??
    37

    View Slide

  38. $bar = (
    $foo
    ? FuncA()
    : (unset)FuncB()
    );

    View Slide

  39. $bar = (
    $foo
    ? FuncA()
    : (unset)FuncB()
    );
    if($foo) {
    $bar = FuncA();
    } else {
    FuncB();
    $bar = null;
    }

    View Slide

  40. © 2014 John Bafford php[world] 2014 — 11/13/2014
    Controlling Runaway
    Functions
    40

    View Slide

  41. © 2014 John Bafford php[world] 2014 — 11/13/2014
    Controlling Runaway Functions
    • PHP has limited multithreading support
    • There’s the pthreads pecl module, but it’s unlikely you
    have --enable-maintainer-zts enabled
    41

    View Slide

  42. A tick is an event that occurs for every N low-level tickable statements
    executed by the parser within the declare block. The value for N is
    specified using ticks=N within the declare block's directive section.
    declare(ticks = 1);

    View Slide

  43. © 2014 John Bafford php[world] 2014 — 11/13/2014
    Method 1
    SIGALRM
    43

    View Slide

  44. class LimitExecutionAlarm {
    function __construct($time, $fn) {
    $this->limit = $time;
    $this->fn = $fn;
    }
    function run() {
    pcntl_signal(SIGALRM, function() {
    echo “HALT!\n";
    exit;
    });
    pcntl_alarm($this->limit);
    $fn = $this->fn;
    $fn();
    echo "Stopped.\n";
    }
    }
    function slowFunc()
    {
    for($x = 0;; $x++)
    {
    echo "Iteration $x\n";
    sleep(1);
    }
    }
    $slow = new LimitExecutionAlarm(

    10,
    ‘slowFunc'
    );
    $slow->run();

    View Slide

  45. © 2014 John Bafford php[world] 2014 — 11/13/2014
    Method 2
    Modify the Original Function
    45

    View Slide

  46. class LimitExecutionThrottleable {
    function __construct($time, $fn) {
    $this->limit = $time;
    $this->fn = $fn;
    }
    function run() {
    $halt = false;
    pcntl_signal(SIGALRM,
    function() use(&$halt) {
    $halt = true;
    });
    pcntl_alarm($this->limit);
    $fn = $this->fn;
    $fn($halt);
    echo "Stopped.\n";
    }
    }
    function slowFuncThrottleable(&$halt = false)
    {
    for($x = 0;; $x++)
    {
    echo "Iteration $x\n";
    sleep(1);
    if($halt)
    {
    echo "halt requested\n";
    break;
    }
    }
    }
    $slow = new LimitExecutionThrottleable(
    10,
    ‘slowFuncThrottleable'
    );
    $slow->run();

    View Slide

  47. © 2014 John Bafford php[world] 2014 — 11/13/2014
    Method 3
    fork
    47

    View Slide

  48. class LimitExecutionFork {
    function run() {
    $pid = pcntl_fork();
    if($pid == -1) { //error
    } else if($pid) { //parent
    echo "Forked $pid\n";
    $done = false;
    pcntl_signal(SIGALRM,
    function() use($pid) {
    if(!$done) {
    posix_kill($pid, SIGTERM);
    echo "Killed $pid.\n”;
    }
    });
    pcntl_alarm($this->limit);
    $status = false;
    $child = pcntl_wait($status);
    $done = true;
    } else { //child
    $fn = $this->fn;
    $fn();
    exit;
    }
    }
    }
    function slowFunc()
    {
    for($x = 0;; $x++)
    {
    echo "Iteration $x\n";
    sleep(1);
    }
    }
    $slow = new LimitExecutionFork(
    10,
    ‘slowFunc'
    );
    $slow->run();

    View Slide

  49. © 2014 John Bafford php[world] 2014 — 11/14/2014
    https://joind.in/talk/view/11915
    !
    John Bafford!
    http://bafford.com — @jbafford — [email protected]
    !
    The Brick Factory!
    http://thebrickfactory.com — @thebrickfactory — [email protected]
    Questions?
    49

    View Slide

  50. © 2014 John Bafford php[world] 2014 — 11/14/2014
    https://joind.in/talk/view/11915
    !
    John Bafford!
    http://bafford.com — @jbafford — [email protected]
    !
    The Brick Factory!
    http://thebrickfactory.com — @thebrickfactory — [email protected]
    Thank You!
    50

    View Slide