Explanation

PHP has some holes in its' syntax and occasionally in development a programmer will step in them. This can lead to much frustration as these syntax holes seem to exist for no reason. For example, one can't easily create an array and access an arbitrary element of that array on the same line (func1()[100] is not valid PHP syntax). The workaround for this issue is to use a temporary variable and break the statement into two lines, but sometimes that can lead to very verbose, clunky code.

Challenge

I know of a few of these holes (I'm sure there are more). It is quite hard to even come up with a solution, let alone in a code-golf style. Winner is the person with in the least characters total for all four Syntax Holes.

Rules

  1. Statement must be one line in this form: $output = ...;, where ... doesn't contain any ;'s.
  2. Only use standard library functions (no custom functions or eval allowed)
  3. Statement works identically to the assumed functional of the non-working syntax (even in cases that it fails).
  4. Statement must run without syntax error of any kind with E_STRICT | E_ALL.

Syntax Holes

  1. $output = func_return_array()[$key]; - accessing an arbitrary offset (string or integer) of the returned array of a function
  2. $output = new {$class_base.$class_suffix}(); - arbitrary string concatenation being used to create a new class
  3. $output = {$func_base.$func_suffix}(); - arbitrary string concatenation being called as function
  4. $output = func_return_closure()(); - call a closure being returned from another function

Comments

Array dereferencing (your 1. syntax hole) has already been committed to trunk by Felipe Pena.

Written by Artefacto

@Artefacto That's amazing news! Last whispers I heard was it being was ignored. Do you have a link for that?

Written by Kendall Hopkins

I think this exercise is pointless. Less characters is different from more clear/more efficient.

Written by Artefacto

@Kendall wiki.php.net/rfc/functionarraydereferencing

Written by Maerlyn

@Kendall Hopkins svn.php.net/viewvc?view=revision&revision=300266

Written by Artefacto

Because that's the point of code golf, to create clean code...

Written by Kendall Hopkins

For just PHP? That's not really the spirit of code golf, which is usually language-agnostic.

Written by waiwai933

@Artefacto Thanks, looks like 5.4 is moving in a good direction.

Written by Kendall Hopkins

The last three are trivial with call_user_func (2. with ReflectionClass). For 1., I don't really know without triggering E_STRICT.

Written by Artefacto

I know the last two are trivial, but how would you do the class one using call_user_func?

Written by Kendall Hopkins

call_user_func(array(new ReflectionClass($class_base.$class_suffix), "newInstance")) BTW, I suppose you don't want eval...

Written by Artefacto

Ya, no eval, added it to the rules.

Written by Kendall Hopkins

The first one you can do with next(array_slice(func(), $index, 1))

Written by intuited

err whoops that only works for numeric accesses

Written by intuited

you want next(array_intersect_key(func(), array($key => 0)))

Written by intuited

@intuited Yes, I though that, but it gives a strict warning. I also thought ArrayIterator + RegexIterator, but the iterator has to be rewinded before it gives anything.

Written by Artefacto

Though I think I broke rule #3, maybe array_shift or something else as a replacement for next would fix that.

Written by intuited

@Artefacto: ah okay hmm maybe not so easy then.

Written by intuited

@intuited It very close, but if the key doesn't exist it doesn't trigger the correct error.

Written by Kendall Hopkins

Maybe "1. use trunk" is a solution :p

Written by Artefacto

Accepted Answer

The only solution I see involves a temporary variable, so there is some (minimal) namespace pollution. Any way of tightening the temporary variable code would shorten all 4 of these:

<?php

error_reporting(E_ALL | E_STRICT);

// 1
function func_return_array() { return array(0 => 'hello'); }
$key = 0;

$output = ${!${''}=func_return_array()}[$key];

echo '1: ' . $output . "\n";


// 2
class Thing {}
$class_base = 'Thi'; $class_suffix = 'ng';

$output = new ${!${''}=$class_base.$class_suffix}();

echo '2: ';
var_dump($output);


// 3
$func_base = 'func_'; $func_suffix = 'return_array';

$output = ${!${''}=$func_base.$func_suffix}();

echo '3: ';
var_dump($output);


// 4
function func_return_closure() {
    return function() {
        return 'This is a closure';
    };
}

$output = ${!${''}=func_return_closure()}();

echo '4: ';
var_dump($output);

Output:

1: hello
2: object(Thing)#1 (0) {
}
3: array(1) {
  [0]=>
  string(5) "hello"
}
4: string(17) "This is a closure"
Written by Shaun
This page was build to provide you fast access to the question and the direct accepted answer.
The content is written by members of the stackoverflow.com community.
It is licensed under cc-wiki