pixel is in Charge


01.11.2014   01:23

I'm Giving A Talk Today!

Apologies for the short notice--I've been rushed just trying to get the darn thing ready--but I will be giving a talk at Iowa Code Camp on Saturday, November 1st.

If you can't attend, or want to review my talk before/after I give it, you can find it here. Feel free to offer any feedback. It's much too late to make major changes at this point, but feedback is welcome regardless.

(Technically the talk is about PHP, but tagged Lisp because I blame Common Lisp for inspiring a bunch of it.)

Ze "official" blog URL has changed, this is merely a cross-post for your reading convenience. You'll have to click through to read comment count unavailable comments or leave your own.


21.09.2014   18:12

Typehint Conversion Caveat Explained

I was highly amused by the reactions to my previous post on the programming and php subreddits. So I spent a little time to isolate the typehint conversion optional argument issue.

It’s not me, it’s PHP. And frankly, I don’t understand the point of the backtrace going to the trouble of making things references if doing things with those references isn’t even supported.

That bug description isn’t entirely accurate as to what’s going on, however, as some test cases show.

<?php

function f(int $a, int $b = null, int $c = null) {
  error_log(json_encode([$a, $b, $c]));
  error_log(json_encode(func_get_args()));
}

function changeArg($code, $str) {
  preg_match('/^Argument (\\d+) /', $str, $m);
  $i = $m[1]-1;
  $bt = debug_backtrace(null, 2);
  ++$bt[1]['args'][$i];
  return true;
}

set_error_handler('changeArg', E_ALL);

f(3, 2, 1);

Outputs:

[4,2,1]
[4,3,2]

Note that the required argument changes, but the optional argument does not. Also note that func_get_args() returns the altered argument, in disagreement with the actual argument.

Where it gets interesting is if we alter that $i to be $i+1. That is, if we change the argument after the one we got an error about.

<?php

function f(int $a, int $b = null, int $c = null) {
  error_log(json_encode([$a, $b, $c]));
  error_log(json_encode(func_get_args()));
}

function changeArg($code, $str) {
  preg_match('/^Argument (\\d+) /', $str, $m);
  $i = $m[1]-1;
  $bt = debug_backtrace(null, 2);
  if (count($bt[1]['args']) > $i+1) {
    ++$bt[1]['args'][$i+1];
  }
  return true;
}

set_error_handler('changeArg', E_ALL);

f(3, 2, 1);

Outputs:

[3,3,2]
[3,3,2]

Then the change sticks, and the optional argument is modified.

By switching to $i-1, you’ll notice that even the required argument fails to be modified. Which means in the default case where one tries to modify the argument an error was triggered about, the argument’s reference is being broken slightly earlier for optional arguments than for required arguments. That, to me, strongly suggests a bug, because the behavior is inconsistent.

But my use-case isn’t supported, and presumably it doesn’t affect any other use-cases, so I’ll either have to live with it or write a code pre-processor which fixes up the issue. Ah well.

I'm left confused about why there exists such a thing as continuable errors if fixing the error and continuing on isn't supported, but ... PHP isn't exactly known for it's strong sense of feature coherency.

Ze "official" blog URL has changed, this is merely a cross-post for your reading convenience. You'll have to click through to read comment count unavailable comments or leave your own.