3

The PHP debugging tool kint has a strange syntax where certain symbols can be prefixed to functions to alter their behavior, as shown in this guide.

The relevant information:

Modifiers are a way to change Kint output without having to use a different function. Simply prefix your call to kint with a modifier to apply it:

! Expand all data in this dump automatically  
+ Disable the depth limit in this dump  
- Attempt to clear any buffered output before this dump  
@ Return the output of this dump instead of echoing it  
~ Use the text renderer for this dump

Example:

+Kint::dump($data); // Disabled depth limit
!d($data); // Expanded automatically

How does this work?

By looking at the source code it seems that the symbols are being parsed into an array called $modifiers. But how can you do this with PHP? And what is the scope of this, could I do this with other unicode symbols as well, or are the five in question (+, -, ~, !, @) the only ones.

The '@' already has a use in PHP when prefixed, see: What is the use of the @ symbol in PHP?. How can this be overruled?


Edit: A follow-up question to the answers given is how exactly kint bends the (php) rules. For example why the ~ doesn't give a syntax error. Consider this example:

<?php
function d($args) {
  echo $args[0];
}
d([1,2,3]); // prints 1
~d([1,2,3]); // syntax error, unsupported operand types

vs

<?php
require 'kint.php';
~d([1,2,3]); // prints the array with the text renderer with no issues

Edit 2: removed unsubstantiated claim that kint uses eval()

glaux
  • 701
  • 7
  • 20

2 Answers2

2

Original author of Kint here.

Sorry you found it confusing! The operands were added as a shorthand to switch some commonly used settings for common usecase scenarios.

Since Kint already parses the PHP code where it was called from to get and display the names (or expressions) of passed variables that are being dumped, adding the operands was a minor addition to that functionality.

variable name displayed

Note the variable name is displayed ^. As of time of writing Kint is still the only dumper that can do this!


And the actual explanation to the OP question comes from this in-depth answer:

PHP unary operators:

Thus, it is perfectly allowable to prefix function calls with these operators, as long as the function returns a type of value that the operator would normally work on:

function foo() {
    return 0;
}

// All of these work just fine, and generate no errors:
-foo();
+foo();
!foo();
~foo();
raveren
  • 17,799
  • 12
  • 70
  • 83
  • Thank you for addressing this question! I'm still not sure about the *how* though. Is the method outlined in Alex Howanskys linked answer correct: that kint use debug_backtrace() to locate the file, open and read it and then... what exactly happens? How does kint change the behavior of my function? In my example in the OP placing a tilde ~ in front of d() is invalid, because the return type (void) is an unsupported operand type for the 'bitwise not'-operation. But then it follows the kint somehow manipulates the return value, and I think the core of my question was how that happens. – glaux Nov 10 '21 at 08:01
  • Hey, Kint does nothing more than use the operands to switch some internal settings around. If you do $a = ~@d($b); you will get a boolean in $a because the @ forces kint to return but ~ casts the return value to bool. There's no working around that. – raveren Nov 11 '21 at 16:05
  • Like I already mentioned, the operands are a fast and silly (if it works it ain't silly:) method to switch some commonly needed settings. They are not that robust to handle combinations, if you need something more advanced/combined you're better off just explicitly switching the settings around. – raveren Nov 11 '21 at 16:09
  • And yes, like you assumed, Kint parses the file gotten from the debug backtrace using a combined approach of regex and the inbuilt PHP tokenizer, to get the variable names or expressions that were passed to the dump. So it was quite easy to add the operand functionality, which I thought was pretty cool to have, since there were zero side effects :) The parsing part wasn't more difficult than writing your own compiler, if you had that in your university cs course :) – raveren Nov 11 '21 at 16:13
1

Sorry for the late reply. I was just reading the Kint documentation and had the same question. After finding your question I decided to investigate. You may have figured it out by now, but kind actually reads the source code of the file that invoked it to change its behavior based on whether any of these "modifiers" were present.

This behavior is absolutely unpredictable as far as I'm concerned and I can't believe anybody would use this kind of trick as anything but a proof of concept. Notably, because the file must be readable, kint modifiers fail on eval()'d code (which you shouldn't be using to begin with) and perhaps in other unusual cases as well.

Max
  • 913
  • 1
  • 7
  • 18
  • 1
    When a call is performed from a php file, kint can simply unwind the stack to find what called him. If the file was executed by php it can be read by php. It's pretty dependable for 99% of the cases. And one should never use eval. I've yet to come against a valid implementation of eval that cannot be solved in a more secure manner. – Tschallacka Apr 25 '18 at 08:37
  • Thank you, I've updated the question with a follow up as to how exactly this abuse of php is accomplished, I'm really curious. – glaux Apr 25 '18 at 09:14
  • "This behavior is absolutely unpredictable as far as I'm concerned" I am humbled to bewilder and overcome your expectations for what is possible for a decent programmer working on a passion project, but that trick you "can't believe anybody would use" has been fail-safe and fool-proof in over 10 years in various production settings since its inception :) also, see my actual answer to this question :) – raveren Nov 08 '21 at 21:18
  • 1
    @raveren Can confirm, as a user I've never had any issues with this, and in fact I'm amazed at how well it works under production and even in certain FS scenarios. If the file is there, it works! – David Refoua Jan 02 '22 at 12:54