phug-php / phug

Phug - The Pug Template Engine for PHP
https://phug.selfbuild.fr
MIT License
62 stars 3 forks source link

Improve information/details on error in EvalAdapter #32

Closed Jikstra closed 6 years ago

Jikstra commented 6 years ago

When executing php code in phug (including mixins or prefixed with a '-') the thrown error is not very informative. This is because the thrown error of the eval function doesn't prove a lot of information. For example, this is an error message i get (currently migrating a project from pugjs to phug):

PHP Parse error:  syntax error, unexpected '=' in /home/kerle/Workspace/makespace/vendor/phug/renderer/src/Phug/Renderer/Adapter/EvalAdapter.php(13) : eval()'d code on line 383

No idea in which file Phug tried to eval some code or in which line.

I'm currently trying to improve that, here's the current code to at least catch the error of eval:

<?php

namespace Phug\Renderer\Adapter;
use Throwable;
use Exception;
use Phug\Renderer\AbstractAdapter;

class EvalAdapter extends AbstractAdapter
{
    public function display($__pug_php, array $__pug_parameters)
    {
        extract($__pug_parameters);
        //eval('?>'.$__pug_php);
        try {
            eval('?>'.$__pug_php);
        } catch (Throwable $t) {
            throw new Exception('ParseError: '  .  print_r($t->getMessage(), true));
        }
    }
}

Sadly i don't know how to figure out in which file we're currently are and on which line the eval'd statement is, as $__pug_php only contains the php block to execute. Maybe someone give me a hint?

kylekatarnls commented 6 years ago

Phug already track errors to the pug source file if you set the "debug" option to true.

How do you call the render/display? Please give the code were you call Phug.

Note: try-catching an error to re-throw it never help.

Jikstra commented 6 years ago

Phug already track errors to the pug source file if you set the "debug" option to true.

Thanks, good to know. But even with, it doesn't, or at least i don't get to see the pug source file.

How do you call the render/display? Please give the code were you call Phug.

<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);

include_once __DIR__ . '/vendor/autoload.php';
Phug::setOption('debug', true);
echo (Phug::displayFile('src/html/impressum.pug'));

The impressum.pug includes quite a lot of other pug files. To be more exact, it extends a layout which is splitted into various pug templates.

Note: try-catching a error to re-throw it never help.

True, my intention was to get the message of the failed eval, get the pug source file (maybe even with line number or something) and throw a new, nicer/more detailed error. Posted the current source code because for me it wasn't so straight forward to catch a throwable. But didn't work with php since php5.6 and just getting started again. Things changed in the meantime :D

kylekatarnls commented 6 years ago

Note: Phug::displayFile('src/html/impressum.pug') output the result, you should not put echo in front of it.

And parse errors such as unexpected '=' should display like this (with shunk of code, pug source file and line):

pug-html-error Please reset all changes you made in the vendor and update Phug to the last version.

If you have an error catcher or library to handle exceptions/errors, disable it.

Jikstra commented 6 years ago

Removed vendor, installed latest phug. phug versions:

$ cat composer.lock | grep phug | grep -v url | grep -v homepage
            "name": "phug/ast",
                "phug/dev-tool": "^0.1.0"
                "phug",
            "name": "phug/compiler",
                "phug/dependency-injection": "^1.1.2",
                "phug/formatter": "^0.5.37",
                "phug/parser": "^0.5.0",
                "phug/util": "^0.4.0"
                "phug/dev-tool": "^0.1.0",
                "phug",
            "name": "phug/dependency-injection",
                "phug/util": "^0.4.0"
                "phug/dev-tool": "^0.1.0"
                "phug",
            "name": "phug/event",
                "phug/dev-tool": "^0.1.0"
                "phug"
            "name": "phug/formatter",
                "phug/dependency-injection": "^1.3.0",
                "phug/parser": "^0.5.0",
                "phug/util": "^0.4.14"
                "phug/dev-tool": "^0.1.0"
                "phug",
            "name": "phug/lexer",
                "phug/reader": "^0.2.0",
                "phug/util": "^0.4.0"
                "phug/dev-tool": "^0.1.0"
                "phug",
            "name": "phug/parser",
                "phug/ast": "^0.1.0",
                "phug/lexer": "^0.5.6",
                "phug/util": "^0.4.0"
                "phug/dev-tool": "^0.1.0"
                "phug",
            "name": "phug/phug",
                "phug/renderer": "^0.4.0"
                "phug/dev-tool": "^0.1.0"
                "phug"
                "phug",
            "name": "phug/reader",
                "phug/dev-tool": "^0.1.0",
                "phug/util": "^0.3.5"
                "phug",
            "name": "phug/renderer",
                "phug/compiler": "^0.5.0",
                "phug/util": "^0.4.15",
                "js-phpize/js-phpize-phug": "^1.1.2",
                "phug/dev-tool": "^0.1.0"
                "phug",
            "name": "phug/util",
                "phug/event": "^0.1.0"
                "phug/dev-tool": "^0.1.0"
                "phug",

My test.pug:

mixin test($foo, $bar)
    - foo = 'abc'
    p= $foo
    p= $bar

+test('aaa', 'bbb')

My test.php

<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);

include_once __DIR__ . '/vendor/autoload.php';
Phug::setOption('debug', true);
Phug::displayFile('test.pug');

Output when im executing test.php:

$ php test.php 
PHP Parse error:  syntax error, unexpected '=' in /home/kerle/Workspace/makespace/vendor/phug/renderer/src/Phug/Renderer/Adapter/EvalAdapter.php(12) : eval()'d code on line 42

Parse error: syntax error, unexpected '=' in /home/kerle/Workspace/makespace/vendor/phug/renderer/src/Phug/Renderer/Adapter/EvalAdapter.php(12) : eval()'d code on line 42

And my php version is 7.2.3

Note: When i have my test.pug file like this:

foo(date=new Date(0))

I get a similiar output like you, but still it misses the displayFile part, or any helpful information in which file the error is. I want to migrate pug project to phug and of course there are some incompatibility problems with the js stuff (i saw there's some js executer or something, but i prefer a php code base). And especially if the pug template is getting included in the nth level, some more details on the file (and at best the line number) would be a good thing to have.

$ php test.php 
PHP Fatal error:  Uncaught Error: Class 'Date' not found in /home/kerle/Workspace/makespace/vendor/phug/renderer/src/Phug/Renderer/Adapter/EvalAdapter.php(12) : eval()'d code:204
Stack trace:
#0 /home/kerle/Workspace/makespace/vendor/phug/renderer/src/Phug/Renderer/Adapter/EvalAdapter.php(12): eval()
#1 /home/kerle/Workspace/makespace/vendor/phug/renderer/src/Phug/Renderer/Partial/AdapterTrait.php(140): Phug\Renderer\Adapter\EvalAdapter->display('<?php $pugModul...', Array)
#2 /home/kerle/Workspace/makespace/vendor/phug/util/src/Phug/Util/SandBox.php(38): Phug\Renderer->Phug\Renderer\Partial\{closure}()
#3 /home/kerle/Workspace/makespace/vendor/phug/renderer/src/Phug/Renderer/Partial/AdapterTrait.php(100): Phug\Util\SandBox->__construct(Object(Closure), NULL)
#4 /home/kerle/Workspace/makespace/vendor/phug/renderer/src/Phug/Renderer/Partial/AdapterTrait.php(142): Phug\Renderer->getNewSandBox(Object(Closure))
#5 /home/kerle/Workspace/makespace/vendor/phug/renderer/src/Phug/Renderer/Partial/AdapterTrait.php(206): Phug\Renderer->g in /home/kerle/Workspace/makespace/vendor/phug/renderer/src/Phug/Renderer/Partial/Debug/DebuggerTrait.php on line 167

Fatal error: Uncaught Error: Class 'Date' not found in /home/kerle/Workspace/makespace/vendor/phug/renderer/src/Phug/Renderer/Adapter/EvalAdapter.php(12) : eval()'d code:204
Stack trace:
#0 /home/kerle/Workspace/makespace/vendor/phug/renderer/src/Phug/Renderer/Adapter/EvalAdapter.php(12): eval()
#1 /home/kerle/Workspace/makespace/vendor/phug/renderer/src/Phug/Renderer/Partial/AdapterTrait.php(140): Phug\Renderer\Adapter\EvalAdapter->display('<?php $pugModul...', Array)
#2 /home/kerle/Workspace/makespace/vendor/phug/util/src/Phug/Util/SandBox.php(38): Phug\Renderer->Phug\Renderer\Partial\{closure}()
#3 /home/kerle/Workspace/makespace/vendor/phug/renderer/src/Phug/Renderer/Partial/AdapterTrait.php(100): Phug\Util\SandBox->__construct(Object(Closure), NULL)
#4 /home/kerle/Workspace/makespace/vendor/phug/renderer/src/Phug/Renderer/Partial/AdapterTrait.php(142): Phug\Renderer->getNewSandBox(Object(Closure))
#5 /home/kerle/Workspace/makespace/vendor/phug/renderer/src/Phug/Renderer/Partial/AdapterTrait.php(206): Phug\Renderer->g in /home/kerle/Workspace/makespace/vendor/phug/renderer/src/Phug/Renderer/Partial/Debug/DebuggerTrait.php on line 167
kylekatarnls commented 6 years ago

First the error is the missing $. If you don't use JS expressions (see https://en.phug-lang.com/#use-javascript-expressions), then you need $ for your variables as in PHP.

mixin test($foo, $bar)
    - $foo = 'abc'
    p= $foo
    p= $bar

+test('aaa', 'bbb')

I will inspect why the error has not a proper stack trace.

Jikstra commented 6 years ago

First the error is the missing $. If you don't use JS expressions (see https://en.phug-lang.com/#use-javascript-expressions), then you need $ for your variables as in PHP.

First, thanks for your really fast replies :) Next, the missing $ was intented to show the problem i have. And updated my post after your answer to give more details.

kylekatarnls commented 6 years ago

OK, I get the problem, parse errors cannot be caught in eval so you need to use another adapter such as stream or file:

<?php

include_once __DIR__.'/vendor/autoload.php';

Phug::setAdapterClassName(\Phug\Renderer\Adapter\FileAdapter::class);
Phug::setOption('debug', true);
Phug::displayFile('test.pug');

Outputs:

Fatal error: Uncaught ParseError: syntax error, unexpected '=' in C:\Users\bastien.miclo\Perso\phug-php\phug\vendor\phug\renderer\src\Phug\Renderer\Partial\Debug\DebuggerTrait.php on line 167

Phug\RendererException: ParseError in C:\Users\bastien.miclo\Perso\phug-php\phug\test.pug:
syntax error, unexpected '=' on line 2, offset 5

    1 | mixin test($foo, $bar)
>   2 |     - foo = 'abc'
------------^
    3 |     p= $foo
    4 |     p= $bar
    5 |
    6 |
    7 | +test('aaa', 'bbb')
 in C:\Users\bastien.miclo\Perso\phug-php\phug\vendor\phug\renderer\src\Phug\Renderer\Partial\Debug\DebuggerTrait.php on line 167

Call Stack:
    0.0002     362848   1. {main}() C:\Users\bastien.miclo\Perso\phug-php\phug\d.php:0
    0.6978    3260288   2. Phug\Phug::displayFile() C:\Users\bastien.miclo\Perso\phug-php\phug\d.php:7
    0.6981    3260400   3. Phug\Renderer->displayFile() C:\Users\bastien.miclo\Perso\phug-php\phug\src\Phug\Phug.php:208
    0.6981    3260752   4. Phug\Renderer->callAdapter() C:\Users\bastien.miclo\Perso\phug-php\phug\vendor\phug\renderer\src\Phug\Renderer.php:250
    1.4954    4707192   5. Phug\Renderer->handleHtmlEvent() C:\Users\bastien.miclo\Perso\phug-php\phug\vendor\phug\renderer\src\Phug\Renderer\Partial\AdapterTrait.php:219
    1.4955    4707568   6. Phug\Renderer->handleError() C:\Users\bastien.miclo\Perso\phug-php\phug\vendor\phug\renderer\src\Phug\Renderer\Partial\AdapterTrait.php:164

This is in CLI mode, but you get an HTML equivalent in browser.

Jikstra commented 6 years ago

parse errors cannot be caught in eval

They can, as shown in my example code. But you need to build a new exception from it, as the eval'd exception is quite unhelpful.

With your test.php the error details are definetly better (thanks), but still not best. I guess the php block is getting put into a file and then required. This improves things, but still (or in my opinion the best way would be) to catch a ParseError and modify so that it points to the real pug file. Something like this:

PHP Fatal error:  Uncaught Phug\...\???: Failed to parse: syntax error, unexpected '='
Near:  
Line: 2 
Offset: xxx
Path: /home/xxx/test.pug in /home/xxx/vendor/phug/lexer/src/xxxxx.php:486
Stack trace:
.....

What i get is:

$ php test.php 

PHP Fatal error:  Uncaught ParseError: syntax error, unexpected '=' in /tmp/pug2O2GM3:42
Stack trace:
#0 /home/kerle/Workspace/makespace/vendor/phug/renderer/src/Phug/Renderer/Partial/AdapterTrait.php(140): Phug\Renderer\Adapter\FileAdapter->display('<?php if (!isse...', Array)
#1 /home/kerle/Workspace/makespace/vendor/phug/util/src/Phug/Util/SandBox.php(38): Phug\Renderer->Phug\Renderer\Partial\{closure}()
#2 /home/kerle/Workspace/makespace/vendor/phug/renderer/src/Phug/Renderer/Partial/AdapterTrait.php(100): Phug\Util\SandBox->__construct(Object(Closure), NULL)
#3 /home/kerle/Workspace/makespace/vendor/phug/renderer/src/Phug/Renderer/Partial/AdapterTrait.php(142): Phug\Renderer->getNewSandBox(Object(Closure))
#4 /home/kerle/Workspace/makespace/vendor/phug/renderer/src/Phug/Renderer/Partial/AdapterTrait.php(206): Phug\Renderer->getSandboxCall('<?php if (!isse...', 'display', 'test.pug', NULL, Object(Closure), Array)
#5 /home/kerle/Workspace/makespace/vendor/phug/renderer/src/Phug/Renderer.php(251): Phug\Renderer->callAdapter( in /home/kerle/Workspace/makespace/vendor/phug/renderer/src/Phug/Renderer/Partial/Debug/DebuggerTrait.php on line 167

It does not contain the real line number.

kylekatarnls commented 6 years ago

Goth, confirmed, I just installed PHP 7.2 and this break the error construction.

kylekatarnls commented 6 years ago

Bad track, in fact it's not about the PHP version, it's about xdebug installed and enabled or not.

Right now, the quick way to get full errors stack traces is to install and enable xdebug in your PHP 7.2 install (beware of the which you use if you have multiple ones like CLI, Apache, etc.)

kylekatarnls commented 6 years ago

Fixed via https://github.com/phug-php/renderer/releases/tag/0.4.1

Jikstra commented 6 years ago

@kylekatarnls Thanks for fixing, FileAdapter works as should, the error highlighting is super helpful :) Can i donate some money to you somehow?

kylekatarnls commented 6 years ago

Hi, thanks a lot for your interest, I'm discussing with the team about some donate button to help us on our hosting/domain fees.