
PHP doesn't need 'finally' - mfukar
http://bugs.php.net/bug.php?id=32100
======
jrockway
Can't you just implement finally in "userspace"? In Perl, you can implement it
with object destruction -- you make an instance of an object whose destructor
does the cleanup you want, and when it goes out of scope (exception thrown,
return, etc.), the cleanup code is run.

It's extremely common to write code like:

    
    
        sub work_in_tmpdir(&) {
            my $cwd = cwd;
            my $guard = guard { chdir $cwd };
            chdir mktmp;
            $_[0]->();
        }
    

Then you can safely work in a temporary directory:

    
    
        print cwd; # /home/jon
        work_in_tmpdir { print cwd; die "OH NOES" }; # /tmp/3sdjkh387dh
        print cwd; # /home/jon
    

If this doesn't look enough like Java, that's easy to fix:

    
    
        sub try(&;@) {
            my ($code, %args) = @_;
            my $guard;
            $guard = guard { $args{finally}->() }
                if exists $args{finally};  
            my $result = eval { $code->() };
            if($args{catch} && !$result){
                $args{catch}->($@);
            }
            return $result;
        }
        catch(&;@) {
            return catch => @_;
        }
        finally(&) {
            return finally => $_[0];
        }
    

(+) Now you can say:

    
    
        try     { something_exceptional }
        catch   { warn "Something bad happened: $_[0] }
        finally { cleanup };
    

No language feature or bug tracker rant-fest required! And, I'm pretty sure
that you can abuse destructors in PHP to get exactly the same result. (In
Perl, that "guard" function from the Guard module is implemented something
like: class Foo { has 'cleanup' => (is => 'ro', isa => CodeRef ); sub DESTROY
{ $self->cleanup->() } }; sub guard(&){ return Foo->new( cleanup => $_[0] ) })

(+) Also, don't cut-n-paste this code into your apps. It misses special cases.
use Try::Tiny, TryCatch, etc. from the CPAN.

~~~
bad_user
That's a neat example, but you're abusing Perl's syntax for that syntactic-
sugar, and it doesn't work like that in PHP (e.g. parens cannot be omitted,
and does this code even compile with "use strict"?)

~~~
jrockway
It compiles with "use strict", and it's not abuse.

The reason you can't compile it is because guard is not defined, nor are cwd,
cleanup, and the other placeholder functions I used. When you are relying on
the parser to add parens for you (and let you omit "sub"), you have to have
the function in scope. Compare:

    
    
        use strict;
        sub foo { bar }
    

And

    
    
        use strict;
        sub bar;
        sub foo { bar };

~~~
bad_user
"abuse" was not the word I was looking for: I meant you're using Perl's
syntactic freedom, and this trick does not work with PHP.

------
jaekwon

      ... it is wrong design. Since obviously you are using the exceptions as control flow.
    

What convoluted understanding of "control flow" makes an exception unworthy of
use as control flow?

Exceptions aren't bugs, they're simply exceptional conditions. If you use them
right they pose no problem but serve to make the code more legible.

~~~
blahpro
I find it laughable that they’re arguing this from the "don’t abuse exceptions
as control flow" angle considering that PHP 5.3 introduced goto.

~~~
dan_netwalker
Oh, great, another way for the rails nazies here at work to make fun of php...
-_-U

~~~
jaekwon
PHP is like legos or loxblox, mmmkay? And I'm not saying legos aren't awesome,
or that you can't build a house out of it. Absolutely you can.

~~~
dan_netwalker
Yeah, I know. But working on a wood statue with a humble knife should not be
an excuse for the chainsaw guy to call you a dumb bastard for not be doing the
statue with the chainsaw, "like proper men should do". Yes, the quoted phrase
was actually heard on my office. Go figure...

( ...and I don't have anything against ruby. I'm learning rails.
www.railsforzombies.com is great. In fact, my php is made on cakephp and
lithium, which are pretty similar to rails... )

------
dan_netwalker
Ok, wait. Time out. What whould be the difference between:

try{ some ifs ... return x ... more ifs ... throw ... return y }catch{ handle
exceptions }finally{ do_something_finally() }

and

try{ some ifs ... return x ... more ifs ... throw ... return y }catch{ handle
exceptions } do_something_finally()

I'm missing something, I'm not?

~~~
yummyfajitas
In this case, do_something_finally() will never be called.

    
    
        try {
            throw new IOException("bad");
        } catch ( NotAnIOException e) {
            System.out.println("This is something I expected to happen.");
        }
        do_something_finally();
    

With a finally block, it would be, and the IOException would then be bubbled
up to the caller. Without finally, you need to do this:

    
    
        try {
            throw new IOException("bad");
        } catch ( NotAnIOException e) {
            System.out.println("This is something I expected to happen.");
        } catch (Exception e) {
            do_something_finally();
            throw e;
        }
        do_something_finally();

~~~
dan_netwalker
Thanks, now that has a lot more sense

------
rodp
A programming language is a tool and its syntax is its UI. PHP community
doesn't get this. They never have. Just because you can empirically prove that
a language doesn't need a feature, it doesn't mean you shouldn't add it if
it's obvious that most developers would _enjoy_ using it.

------
wvenable
Just like with C++ (which also doesn't have finally) you can use RAII
techniques with PHP. Object destructors will get called when your object goes
out of scope. I use this to clean up resources (mainly rollback transations)
in the case of exceptions.

In fact, now with PHP 5.3 and closures one could emulate finally quite easily:
just create an object that runs the closure on destruction and it will be
called at the end of the block.

Finally would still, however, be a welcome addition to the language.

------
morgo
The example is the wrong case. Unless you are using MyISAM tables (hint: 90%+
of the time you shouldn't), there's rarely a situation to LOCK TABLES as
described.

Using transactions would make more sense:

    
    
      try {
        mysql_query("START TRANSACTION");
        // ... do lots of queries here
        mysql_query("COMMIT");
      } catch(Exception $e) {
        mysql_query("ROLLBACK");
      }

~~~
dlsspy
You left out the code where you acquire the database connection and need to
release it before returning as well as propagate the success or failure of the
operation.

------
DjDarkman
I don't think 'finally' is mandatory, I have never missed it, sure it may be
syntactic sugar 1% of the time, but are we developing for the rare cases now?

------
morgo
What irritates me about this thread is the sense of entitlement from people
who file bugs.

If helly wants to say "there was a discussion about this on the internals
list, and the decision was no" he doesn't have to justify anything more.

If they still care enough, they can dig up the internals thread and re-spark
discussion.

~~~
jwatzman
One of the notes on the report is someone who did try to dig up the discussion
and couldn't find it, only a bunch of people saying without reasons "we do not
need finally". It seems polite to me for someone who knows when/where said
discussion was to link to it.

------
crad
So if I read that right, you don't need finally because you can unlock mysql
tables when catching the exception? That's brilliant. Clearly as far as the
PHP team is concerned, there is no other use for PHP than using it with MySQL.

~~~
shub
The person who submitted the bug included an example of finally with MySQL,
and the PHP guy was holding to that theme so that his response would be as
clear as possible. So really, you should be blaming some random guy on the
Internet for having no other use for PHP than using it with MySQL, which is
more than likely true.

------
joelmichael
This looks like a PHP version of the Ruby "ensure".
[http://web.njit.edu/all_topics/Prog_Lang_Docs/html/ruby/synt...](http://web.njit.edu/all_topics/Prog_Lang_Docs/html/ruby/syntax.html#begin)

------
hackermom
Syntactic sugar would be the right term for this, I guess. I think everyone
who has dealt in languages not having Try-Finally can recall a case or two
where it would've felt smooth and tidy to have access to Finally - but never,
ever a case where they absolutely required it. No one is having problems in
C/++ because of this. No one is having problems in PHP, either.

And saying this will probably get me the flood of down votes, but this has
always struck me as being something that is a language "requirement" only in
people who have an itch in a hard-to-reach place in the engineering department
of their brain - no offense meant. They need it for their sense of order, not
for their software.

~~~
Nitramp
Finally makes it much more easy, and much more readable, to do the right
thing. Not having finally means duplicated code and harder to follow methods
where resources have to be managed, and for most developers, this simply means
resources are not managed properly at all.

C++ doesn't need finally because it has deterministic destructors, which are
used to emulate finally clauses. In my opinion, destructors can cause less
readable/predictable code than a proper finally block, but that might be
matter of taste.

Comment from the language maintainer: _The only difference is the second
example does rethrow the exception. Though this is still possible (however
much more to type) it is wrong design. Since obviously you are using the
exceptions as control flow._

This seems quite strange. Finally is a construct to manage control flow, and
it's essential to control flow during error conditions. He seems to prefer
just swallowing a (potentially critical) exception. Either I'm misreading him,
or I think he fails to understand the point of either finally, or exception
handling in general.

~~~
wvenable
> C++ doesn't need finally because it has deterministic destructors

PHP has deterministic destructors as well. Using them is how I get around the
lack of finally -- destructors do the clean up.

~~~
TimJYoung
Question: when are PHP's object destructors called ? I can see some issues
with external resources if an object instance hangs around until it is garbage
collected. PHP might not have an issue with this if it does GC for every page
load, but other languages like the .NET languages can experience serious
issues if you don't release external resources using a finally block, and
rather rely on the destruction of the object to release them. In such a case,
the destruction may take place a long time after the initial acquisition of
the external resources.

My point is that object lifetime <> external resource usage duration in all
cases.

~~~
wvenable
> when are PHP's object destructors called ?

As soon as there are no more references to it. PHP is reference counted (with
cycle detection). As soon as the variable containing an object goes out of
scope, the destructor will be called.

The fact that Java/C# destructors aren't called immediately (and may not be
called at all) is the primary reason that Java has the finally block (C++
doesn't) and why C# also has the using statement.

~~~
TimJYoung
Thanks for the response. I knew that PHP was reference counted, but what I was
asking (not particularly well) was more along the lines of: is it possible to
have objects live longer than the scope of a single script ? IOW, is there a
point at which the PHP runtime decides that it is going to collect/reclaim
everything, similar to a process termination in the OS ? Or is it literally
possible to implicitly allocate objects in a global fashion and have them
stick around until the PHP runtime itself is terminated ? Thanks again.

~~~
wvenable
When a single script terminates, all the memory is deallocated. Basically, as
you said, it's just like process termination in the OS.

~~~
dan_netwalker
Well, in fact you could serialize/unserialize the objects and store them
somewhere, making use of the "magic" functions __sleep() and __wakeup(), if I
recall correctly. But yes, as soon as the web server ends the response or the
script gets to the end, it's finished

