Skip to content

Conversation

@ircmaxell
Copy link
Owner

This adds support for try/catch. Though it is not complete.

Presently, Traverser doesn't fully implement correctly, as it won't traverse the CatchTarget property on the block. This will need to be fixed before merge.

eric-therond and others added 2 commits July 2, 2025 16:40
…ly traverse try/catch edges as they aren't returned in the sub-node call
@ircmaxell ircmaxell mentioned this pull request Aug 6, 2025
… color Catches to type to make it clearer and easier to follow
@ircmaxell
Copy link
Owner Author

Added colors and changed line types for exception edges to make the image easier to understand.

<?php
try {
    if ($foo) {
        doBar();
    } else {
        doBaz();
    }
} catch (OtherException $e) {
    echo "e";
} catch (Exception $e) {
    echo "a";
} finally {
    echo "b";
}
echo "c";

Renders as

Screenshot 2025-08-06 at 10 55 12 AM

eric-therond and others added 2 commits August 8, 2025 18:19
Clean up try/catch support, changing `Op::getSubBlock()` logic to return an associative array of variable => value instead of variable-variables.
@ircmaxell ircmaxell mentioned this pull request Aug 8, 2025
@ircmaxell
Copy link
Owner Author

@eric-therond I merged in your changes. Thanks a ton for that so far.

I tried testing with a more aggressive and convoluted flow. I turned of

<?php
try {
    try {
        a:
        echo "a";
        try {
            echo "aa";
        } catch (OtherException $e) {
            echo "ab";
        } finally {
            echo "abc";
        }
    } finally {
        echo "b";
    }
} finally {
    echo "c";
}
echo "d";
goto a;

It's generating what looks on the surface to be the correct text dump:

Block#1
    Stmt_Try
        body: Block#2
        finally: Block#3

Block#2
    Parent: Block#1
        finallyTarget: Block#3
    Stmt_Try
        body: Block#4
        finally: Block#5

Block#3
    Parent: Block#1
    Terminal_Echo
        expr: LITERAL('c')
    Stmt_Jump
        target: Block#6

Block#4
    Parent: Block#2
        finallyTarget: Block#5
    Stmt_Jump
        target: Block#7

Block#5
    Parent: Block#2
        finallyTarget: Block#3
    Terminal_Echo
        expr: LITERAL('b')
    Stmt_Jump
        target: Block#8

Block#6
    Parent: Block#1
    Terminal_Echo
        expr: LITERAL('d')
    Stmt_Jump
        target: Block#7

Block#7
    Parent: Block#4
    Parent: Block#6
        finallyTarget: Block#5
    Terminal_Echo
        expr: LITERAL('a')
    Stmt_Try
        catchTypes[0]: LITERAL('OtherException')
        catchVars[0]: Var#1<$e>
        body: Block#9
        catch[0]: Block#10
        finally: Block#11

Block#8
    Parent: Block#2
        finallyTarget: Block#3
    Stmt_Jump
        target: Block#3

Block#9
    Parent: Block#7
        catchTarget<LITERAL('OtherException')>(Var#1<$e>): Block#10
        finallyTarget: Block#11
    Terminal_Echo
        expr: LITERAL('aa')
    Stmt_Jump
        target: Block#11

Block#10
    Parent: Block#7
        finallyTarget: Block#11
    Terminal_Echo
        expr: LITERAL('ab')
    Stmt_Jump
        target: Block#11

Block#11
    Parent: Block#7
        finallyTarget: Block#5
    Terminal_Echo
        expr: LITERAL('abc')
    Stmt_Jump
        target: Block#12

Block#12
    Parent: Block#7
        finallyTarget: Block#5
    Stmt_Jump
        target: Block#5

And the CFG diagram generated looks solid too (though it is non-obvious since jumps aren't labeled)

Screenshot 2025-08-08 at 2 13 08 PM

And with the optimzier turned on (Traverser enabled):

Screenshot 2025-08-08 at 2 23 37 PM

So overall this looks good to me so far. Anything else missing at this point?

@eric-therond
Copy link
Contributor

Thank you for all your advice and for moving this project forward.

Also, Thinking about it a bit more, I think each of the catch blocks and finally blocks should have every block which has them as a catchtarget as a parent so that controlflow is modeled correctly (phi nodes, etc).

From what you suggested here on another thread, I think this is still missing, I can try to add it later.

@eric-therond
Copy link
Contributor

I created a pull request on parents, I would say it is actually enough if:

  • the only parents of a finally block are catchs blocks and try body block
  • and the only parent of catch blocks is the try body block
  • the only parent of next block is the try body block

?

@eric-therond
Copy link
Contributor

Forget my previous message.

I now understand that in the event of an exception that can occur anywhere, it may be desirable to add an edge from any block in the try body to the catch/finally blocks?

I've fixed the PR in this direction.

@ircmaxell
Copy link
Owner Author

Anything else missing here? Is this ready to merge?

@eric-therond
Copy link
Contributor

Yes it looks ok for me.

@ircmaxell ircmaxell merged commit 7899d23 into master Aug 10, 2025
12 checks passed
@ircmaxell
Copy link
Owner Author

Really well done here, thanks for the back and forth, the polish, and driving it to completion!

@eric-therond
Copy link
Contributor

Thank to you! It's a very interesting project to work on.
A quick request: is it possible to release a new version, 0.8.0 of php-cfg?

@ircmaxell
Copy link
Owner Author

@ircmaxell ircmaxell deleted the TRYCATCH branch August 11, 2025 16:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants