Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>The <a href="https://stackoverflow.com/questions/2321511/">RAII</a> idiom offers a code-level stand-in for a <code>finally</code> block. Create a class that holds callable(s). In the destuctor, call the callable(s).</p> <pre><code>class Finally { # could instead hold a single block public $blocks = array(); function __construct($block) { if (is_callable($block)) { $this-&gt;blocks = func_get_args(); } elseif (is_array($block)) { $this-&gt;blocks = $block; } else { # TODO: handle type error } } function __destruct() { foreach ($this-&gt;blocks as $block) { if (is_callable($block)) { call_user_func($block); } else { # TODO: handle type error. } } } } </code></pre> <h3>Coordination</h3> <p>Note that PHP doesn't have block scope for variables, so <code>Finally</code> won't kick in until the function exits or (in global scope) the shutdown sequence. For example, the following:</p> <pre><code>try { echo "Creating global Finally.\n"; $finally = new Finally(function () { echo "Global Finally finally run.\n"; }); throw new Exception; } catch (Exception $exc) {} class Foo { function useTry() { try { $finally = new Finally(function () { echo "Finally for method run.\n"; }); throw new Exception; } catch (Exception $exc) {} echo __METHOD__, " done.\n"; } } $foo = new Foo; $foo-&gt;useTry(); echo "A whole bunch more work done by the script.\n"; </code></pre> <p>will result in the output: <pre> Creating global Finally. Foo::useTry done. Finally for method run. A whole bunch more work done by the script. Global Finally finally run. </pre></p> <h3>$this</h3> <p>PHP 5.3 closures can't access <code>$this</code> (fixed in 5.4), so you'll need an extra variable to access instance members within some finally-blocks.</p> <pre><code>class Foo { function useThis() { $self = $this; $finally = new Finally( # if $self is used by reference, it can be set after creating the closure function () use ($self) { $self-&gt;frob(); }, # $this not used in a closure, so no need for $self array($this, 'wibble') ); /*...*/ } function frob() {/*...*/} function wibble() {/*...*/} } </code></pre> <h3>Private and Protected Fields</h3> <p>Arguably the biggest problem with this approach in PHP 5.3 is the finally-closure can't access private and protected fields of an object. Like accessing <code>$this</code>, this issue is resolved in PHP 5.4. For now, <a href="https://stackoverflow.com/q/3722394/90527">private and protected properties</a> can be accessed using references, as Artefacto shows in his <a href="https://stackoverflow.com/a/3722429/90527">answer</a> to a question on this very topic elsewhere on this site.</p> <pre><code>class Foo { private $_property='valid'; public function method() { $this-&gt;_property = 'invalid'; $_property =&amp; $this-&gt;_property; $finally = new Finally(function () use (&amp;$_property) { $_property = 'valid'; }); /* ... */ } public function reportState() { return $this-&gt;_property; } } $f = new Foo; $f-&gt;method(); echo $f-&gt;reportState(), "\n"; </code></pre> <p><a href="https://stackoverflow.com/q/6386733/90527">Private and protected methods</a> can be accessed using reflection. You can actually use the same technique to access non-public properties, but references are simpler and more lightweight. In a comment on the PHP manual page for <a href="http://www.php.net/manual/en/functions.anonymous.php#98384" rel="nofollow noreferrer">anonymous functions</a>, Martin Partel gives an example of a <code>FullAccessWrapper</code> class that opens up non-public fields to public access. I won't reproduce it here (see the two previous links for that), but here is how you'd use it:</p> <pre><code>class Foo { private $_property='valid'; public function method() { $this-&gt;_property = 'invalid'; $self = new FullAccessWrapper($this); $finally = new Finally(function () use (&amp;$self) { $self-&gt;_fixState(); }); /* ... */ } public function reportState() { return $this-&gt;_property; } protected function _fixState() { $this-&gt;_property = 'valid'; } } $f = new Foo; $f-&gt;method(); echo $f-&gt;reportState(), "\n"; </code></pre> <h3><code>try/finally</code></h3> <p><code>try</code> blocks require at least one <code>catch</code>. If you only want <code>try/finally</code>, add a <code>catch</code> block that catches a non-<code>Exception</code> (PHP code can't throw anything not derived from <code>Exception</code>) or re-throw the caught exception. In the former case, I suggest catching <code>StdClass</code> as an idiom meaning "don't catch anything". In methods, catching the current class could also be used to mean "don't catch anything", but using <code>StdClass</code> is simpler and easier to find when searching files.</p> <pre><code>try { $finally = new Finally(/*...*/); /* ... */ } catch (StdClass $exc) {} try { $finally = new Finally(/*...*/); /* ... */ } catch (RuntimeError $exc) { throw $exc } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload