Today, I've pushed something to jnvsor/kint/2.x-dev. I've been working on this for about 3 months now, I've basically rewritten all of Kint from the ground up.
I'd like this to be a starting point for a new major version of kint.
Bugfixes
#50 #175 #203 #197 #182 #177 #176 And probably more too...
Plugins
Lots of kint is very rigid. It's not designed with extensibility in mind. Most of the time you want to customize behaviour you have to edit kint source code yourself. In some of the best cases you have to dump new files inside kint's directory tree. These are bad things for anyone that wants to install an update.
My branch has a very extensive plugin system, to the point where you can pretty much replace both the parsing and rendering systems entirely without ever touching kint source code. This makes it possible for user provided solutions to certain feature requests:
#107 (High prio for over 2 years! :D) #185 #94 #189
#87 : No longer applies: All the config system did was set a few properties on the kint class, you can do that from anywhere and have an easier time of it and a cleaner codebase
Additionally, because the parser/renderer/plugins etc are properly decoupled, it can be meaningfully unit tested. (This provides a start at #26)
In fact, it's so decoupled that if you want you can just call the parser and renderer and leave the main Kint class out of the loop entirely. (TODO: Some plugins get hardcoded info from Kint class, max_str_length
in Kint_Object_Blob
for example)
Internals
Kint master internals are Lovecraftian - peer at them too long and your sanity will be devoured by the great old ones.
Sarcasm aside - kint seems to have been developed very organically, which isn't necessarily bad but tends to add technical debt.
- We have a parser that outputs HTML, so if you want a decorator that doesn't you first have to unparse the HTML (See 2db0845f7a9ac642d09947e6f000e57e3b91ac64 )
- For some reason the parser is actually a child class of the data objects it's supposed to produce (???)
- The parser tries valliantly (And fails miserably) to prevent recursion "ghosts" on referenced arrays at the root level (See #203, #204) I've explained why this can't be done before, but that's a complex topic so I'll leave that for the other issues.
- Parser plugins almost exclusively produce html, so they're by definition reliant on the rich renderer. Checks on
Kint::$enabledMode
are strewn throught the parser system.
- It's a deck of cards. Everything is far too tightly coupled.
Long story short: I gutted everything. Now the parser just returns data, and the renderer takes that data and does whatever with it. The individual parts are all smaller: The rich renderer is 10% smaller, the parser is 40% smaller, the JS renderer (The example for the unparsing problem) is also 40% smaller.
Lots of special case code has been moved from the parser and main kint class into plugins where they belong: Backtrace handling, tabular display, etc
Basically it's a big-ass cleanup and for the most part easier to grep
The catch
Well not catch so much as caveats.
This is a work in progress
While it works fine for basic debugging, most of the plugins aren't ported yet. ClassStatics
, ClassMethods
, Microtime
, Closure
and Trace
have all been ported, but there's still a small mountain worth of missing ones (Including things like the tabular display that used to be hardcoded in the parser)
The plain renderer also hasn't been ported yet, so PLAIN
WHITESPACE
and CLI
output modes won't work till that's done.
It's got a lot of good stuff, but it's not feature parity (Yet)
This is not a stable API
I'm very happy with the way the parser works. I've put a lot of thought into it and it seems to work beautifully. The problem is the renderer.
The renderer needs to know how to take data and turn it into output. Currently, the parser plugins can add a "Class" to a representation (Tab) and the renderer maps that class to a renderer plugin. This works fine but there's no way to alter the way a header is rendered, only a tab. I intend to make large changes to the plugin system until it's working well enough.
Here be monsters.
It's slow
Last I checked the parser was some 1000% faster than the old parser, but the renderer is significantly slower and it all evens out at a 50% slowdown (Last I checked... I've changed a lot since then)
I'm not actually sure why this is - when I stub out all the relevant functions so it's just outputting enough to let me know it's actually outputting at all, it's still far slower. I'm guessing it's some PHP internal optimization - probably something in static methods that PHP deems pure so it caches the result or some such.
All that said, it's not too slow - I don't see any difference in normal use. The pliability benefits of the new plugin system outweigh a speed difference I can't tell exists without tools. I'll take a closer look after I'm satisfied with the API.
It works in PHP 5.1
While I'd like to make a smiley and say this is just a joke about kint's strict version requirements (next month 5.1 will have been EOL for a decade) the truth is it's so old I couldn't find a way to get it working so while it absolutely should work on 5.1 I have NO way of proving that. If anyone can test it for me (Or show me an easy way to do it myself) that would be a big help.
The code style
Code style conversations are always purely subjective. Subjective enough to turn into flame wars so I'm not going to bother rooting for the code style I use here, or against the code style in master.
Instead I'm going to argue on consistency. Consistent code style is good right? We can agree on that right? Right?...
Anyway, I'm not very consistent. I drift between K&R, PSR, trololol-minified-php-ftw, and generally don't have anything consistent enough to write my own code style rules. So I let my computer do it for me.
php-cs-fixer guarantees consistent code. It also lets me write whatever sloppy nonsense I want to then fix it with a simple command. Because it's a program, we could also enforce it alongside a test suite with CI.
There are other purported php formatters out there but of the few I've tried php-cs-fixer is the best (One of them actually changed method naming styles and broke a system on me once... Yay) and the defaults are fairly sane and PSR compliant. Most importantly, I personally can attest that if I stuck with master's code style I'd have been at it for another 3 months :)
What needs to be done
If anyone has any ideas that could clean up the architecture I've made here that would be great
- I want to tweak the rendering system a bit so that plugins can effect headers as well as tabs, so I'll probably end up gutting that for the fifth time.
- It needs to be tested for 5.1 compat
- I need to find out what's going on with rendering performance. This should wait until all plugins are ported as that can effect performance too.
- A lot of plugins need to be ported
- A test suite would be nice, but lets get things working first.
- I want to decouple a few things that shouldn't be in the main Kint class (max_str_length should probably be on the renderer not the Kint class, the Trace plugin should have a configurable alias tracking system, etc)