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

Stupid PHP Tricks

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on.
Avatar for John Bafford 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].

Avatar for John Bafford

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
  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
  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
  4. © 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
  5. 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!
  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!
  7. 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!
  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! php st-ob.php --ob a b c! a:! HelloHelloWorldWorld! ! b:! HelloHelloWorldWorld! ! c:! HelloWorldHelloWorld!
  9. php st-ob.php --ob a b c! a:! HelloHelloWorldWorld! ! b:!

    HelloHelloWorldWorld! ! c:! HelloWorldHelloWorld!
  10. 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 ]]] )
  11. 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!
  12. 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 ]]] )
  13. © 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
  14. © 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
  15. $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 */
  16. $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" */
  17. $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 ) */
  18. $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 ) ) */
  19. function setGreek(&$output) { $output = ['α', 'β', 'ɣ', 'δ']; }

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

    ! ! setGreek($x); print_r($x); ! /* Array ( [0] => α [1] => β [2] => ɣ [3] => δ ) */
  21. 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] => δ ) ) */
  22. $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 ) */
  23. 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; }
  24. <?xml version="1.0" encoding="UTF-8"?> <foo> <bar>one</bar> <bar>two</bar> <baz>three</baz> <baz><quux>four</quux></baz> </foo> Array(!

    [foo] => Array(! [0] => Array(! [bar] => Array(! [0] => one! [1] => two! )! ! [baz] => Array(! [0] => three! [1] => Array(! [quux] => Array(! [0] => four! )! )! )! )! )! )
  25. 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 )
  26. © 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! )!
  27. $bar = ( $foo ? FuncA() : (unset)FuncB() ); if($foo)

    { $bar = FuncA(); } else { FuncB(); $bar = null; }
  28. © 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
  29. 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);
  30. 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();
  31. 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();
  32. 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();
  33. © 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
  34. © 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