A tale of .desktop files in the environment when all we needed to do was to update the alternatives.
Recently I’ve rediscovered running web-apps locally. One was with fabulous git-annex(1) (https://git-annex.branchable.com/) which already showed how aged my local config was but I was too much distracted with other things setting things up properly in the first place.
As the saying goes, you have to do it again anyway, and then more than twice. I’ve heard they call it x/y problem. Humans and computers, sigh. Should do more blogging, though, lets do this.
My reason to go was httrack(1) (https://www.httrack.com/) for archiving a website. As I only use it occasionally, I was pleased to read it has a web-ui. Similar to git-annex(1) it integrates on the Linux desktop so that you can start it from the menu or dash and then your browser opens the application running on a local server. Onwards, it’s just a clicke-di-click on the go.
And there the problem goes: Not my preferred browser that was. This time I took the opportunity to look things up more properly.
Strategy #0: Environmentally Executed in .desktop
First of all let’s check where the .desktop file of the application is. Find all the things:
There we found BROWSER and thought this is what to influence in the .desktop file accordingly. While this may sound clever, and it certainly works as I’ll continue to demonstrate, this was not smart, but more on that later.
(the >&- 2>&- is to close the output and diagnostic channels –stdout 1, stderr 2– for brevity of the example; otherwise may spill diagnostics into the terminal)
Looks good?! In any case, the removal, no example is complete without the uninstall:
Now this solves the original problem: The env(1) utility used in the Exec= line sets the BROWSER environment parameter to gnome-www-browser which is using the one from the desktop settings (at least I believe). In principle this also works in LXDE and other desktop variants, the tooling may be named different, and not all desktops have .desktop files, but then similar ones.
While this was sweet and dandy, the removal at the end has a different reason than uninstalling WebHTTrack again. Which brings us to:
Strategy #1: Update Alternatives
The Debian Alternatives System has the updates-alternatives(1) command that controls such things as well. While it sets the preference for the whole system (and requires therefore sudo(1)), this is actually fine on my desktop machine. It also spares me to re-login only to load a changed configuration.
I only remembered to look into that while writing things up. But better late than never. So now with that strategy, which, as a system setting, has the benefit that it won’t need to be set up for each individual application. And therefore not constant patching around.
This is smart and now my preferred choice.
We can inspect it with the –get-selections option and give it a grep. And there I found the culprit:
$ update-alternatives --get-selections | grep browser
gnome-www-browser auto /usr/bin/google-chrome-stable
infobrowser auto /usr/bin/info
www-browser auto /usr/bin/lynx
x-www-browser auto /usr/bin/google-chrome-stable
For gnome-www-browser and x-www-browser –both a configuration for the desktop web-browser– google-chrome-stable was set. This is exactly what I wanted not. I certainly have it installed for some browser testing initially, but I’m using Vivaldi but forgot to setup those settings?!
For some reasons not really explicable to me, this does not reflect the configuration I have in use in the Gnome desktop itself, certainly this made it hard to grasp for me in the first place.
The BROWSER environment variable set earlier for webhttrack(1) tells the system to use the gnome-www-browser (as we’ve “sed” it to), so somehow it’s still not clear to me why it then was not using Google Chrome but Vivaldi then, while in the alternatives system this was already set. Perhaps because here it’s the system setting, and for Gnome it then looked to pick my user’s desktop setting.
So let’s try with the gnome-www-browser group first:
$ sudo update-alternatives --config gnome-www-browser
There are 4 choices for the alternative gnome-www-browser (providing /usr/bin/gnome-www-browser).
Selection Path Priority Status
------------------------------------------------------------
* 0 /usr/bin/google-chrome-stable 200 auto mode
1 /usr/bin/chromium-browser 40 manual mode
2 /usr/bin/firefox 40 manual mode
3 /usr/bin/google-chrome-stable 200 manual mode
4 /usr/bin/vivaldi-stable 200 manual mode
Press <enter> to keep the current choice[*], or type selection number: 4
update-alternatives: using /usr/bin/vivaldi-stable to provide /usr/bin/gnome-www-browser (gnome-www-browser) in manual mode
Sudo(1) required, update-alternatives with –config <group> asks which setting to use. I’ve chosen 4 here for vivaldi-stable (https://vivaldi.com/). Let’s check how it looks with that setting, we can try it the way
But it is not the right browser still. Rinse and repeat, let’s take x-www-browser now (would have been shorter to type anyway):
$ sudo update-alternatives --config x-www-browser
There are 4 choices for the alternative x-www-browser (providing /usr/bin/x-www-browser).
Selection Path Priority Status
------------------------------------------------------------
* 0 /usr/bin/google-chrome-stable 200 auto mode
1 /usr/bin/chromium-browser 40 manual mode
2 /usr/bin/firefox 40 manual mode
3 /usr/bin/google-chrome-stable 200 manual mode
4 /usr/bin/vivaldi-stable 200 manual mode
Press <enter> to keep the current choice[*], or type selection number: 4
update-alternatives: using /usr/bin/vivaldi-stable to provide /usr/bin/x-www-browser (x-www-browser) in manual mode
$ update-alternatives --display x-www-browser
x-www-browser - manual mode
link best version is /usr/bin/vivaldi-stable
link currently points to /usr/bin/vivaldi-stable
link x-www-browser is /usr/bin/x-www-browser
/usr/bin/chromium-browser - priority 40
/usr/bin/firefox - priority 40
/usr/bin/google-chrome-stable - priority 200
/usr/bin/vivaldi-stable - priority 200
$ sudo update-alternatives --install /usr/bin/x-www-browser x-www-browser /usr/bin/librewolf 200
Et voilá, now the libre wolf hauling at WebHTTrack. Things remain easy again. Looks like they can improve their packaging. But I’m going back to Vivaldi for now, perhaps I should configure that directly:
$ sudo update-alternatives --set x-www-browser /usr/bin/vivaldi-stable
update-alternatives: using /usr/bin/vivaldi-stable to provide /usr/bin/x-www-browser (x-www-browser) in manual mode
$ gtk-launch WebHTTrack >&- 2>&- ; printf 'exit-status: %s\n' $?
exit-status: 0
Once you know how, it’s getting only easier. And faster.
Arg, now was not that much taking care to exit WebHTTrack properly while in testing-frenzy. Cleanup time:
Now as everything is working as wished, I probably continue using httrack on the command line. Freedom of choice.
So in Strategy #0 we edited the .desktop file of an application and were setting the BROWSER parameter to gnome-www-browser which itself was pointing to google-chrome-stable but by doing so it somehow did override to a browser different than Google chrome despite in the alternatives it still showed when looking in there first. This part I don’t really grep, but changing that alternative didn’t work either. So perhaps there is some other delegation for that.
The x-www-browser it is then, as Strategy #1, using Debian update-alternatives has revealed.
Images edited with Gimp, filter Roy Lichtenstein (FX-Foundry Photo/Effects) terminal theme Tilix, editor theme Neovim. No penguins have been harmed in this production.
PHP language changes and until we understand them. Did this caught your attention?
The release of PHP 8.1 is quite some days ago, like November the year before last year, and when I first learned about first class callable syntax (by the RFC, but the manual has it, too) it was like this is a benefit for static code analysis (only).
This one also looks like a nice short for of Closure::fromCallable(<callable>) and comes with the same object and scope bindings:
# first class callable syntax:
strlen(...)($string);
# NOTE: the three dots ... are not an omission
# short form of closure from callable:
Closure::fromCallable("strlen")($string);
Now this example looks quite dull. We could just call strlen(string) and case closed. Obviously we only use it when we want a Closure, not a callable.
Yesterday, I revisited an older answer of mine on Stack Overflow in regard to a very simple, ground working PHP function, get_object_vars().
Using get_object_vars($this) returns all properties within scope, so my answer back in 2012 was to write a global function, pass the object and call get_object_vars() within:
function get_object_public_vars($object) {
return get_object_vars($object);
}
class Foo {
public function getPublicVars() {
return get_object_public_vars($this);
}
}
Sure, that’s not what the OP really has hoped for, because you have to add another global function into your utilities instead of having something at your disposal directly.
It took two more years until 2014 when Brad Kent had the one-liner answer:
public function getPublicVars() {
return call_user_func('get_object_vars', $this);
}
Wait, what? – If calling get_object_vars() directly yields privates, why calling it with call_user_func() as the callable string 'get_object_vars' changes the scope? – Well we don’t know but it passed the year and then with the PHP 7.0.0 release in December 2015 these semantics changed and it was not such a thing any longer. (Change log only, sadly I still couldn’t find a related bug report.)
Now commentators below the answer then were keen to point out that it relies on a bug (again, sadly no references to it), until then sometime Brad edited in telling the required PHP version and otherwise use reflection.
Same for me, this was also my line of defense in my answer and I had reflection in it, too.
But I do not really like to rely on reflection / meta programming during programming as it often demands many more interruptions over time as reflection changes far more often as the language progresses while it is running behind actual progress in the language. Often the code that is produced by it is not robust, it does not feel well.
As create_function() is not an answer for longtime and closures could have it I was looking into them. And there I found a cadeau surprise:
public function getPublicVars() {
return get_object_vars(...)->__invoke($this);
}
The __invoke method is part of PHPs’ final internal Closure class, also known for classes not extending from Closure as magic method that turns an object into a callable.
In this example get_object_vars is turned into a closure and it is bound to the scope of $this/getPublicVars() so that it can obtain all the properties.
However, triggering the __invoke() event moves it far away enough out of scope to return only the public properties similar to call_user_func('get_object_vars') once did.
So thanks to the new PHP 8.1 first class callable syntax it is now again easier to write and to rely on important code functions like get_object_vars() and to draw the thin line between invocations.
Now is this a bug as it was one in call_user_func()? Well, different to call_user_func(), which has only one form of invocation and therfore perhaps required the change, here the Closure has two forms:
# the two forms how to invoke a Closure in PHP:
get_object_vars(...)($this);
get_object_vars(...)->__invoke($this);
Therefore there is a thin line to draw here and get_object_vars(…)($this) allows to call_user_function('get_object_vars', $this) as in PHP 7+ and with __invoke($this) as it was before. For the many other functions that are not scope aware this should not make a difference and we can safely assume that the first, standard form is not affected by it. Therefore the differentiation remains to the caller offered by the implementors’ choice.
Therefore instead of calling it a bug, why not see it as implementation-specified behaviour and call it a feature. It is a one of the Closure from callable and it won’t translate out of it.
# the two forms how to invoke a Closure in PHP:
get_object_vars(...)->__invoke(...)($this);
get_object_vars(...)->__invoke(...)->__invoke($this);
You can make use of __invoke() in your own implementations and resolve the scope issue with it as well. This is PHP 7.0+ code again:
(new class {function __invoke($object) {
return get_object_vars($object);}
})($this);
Or by relying on another method of Closure, bindTo() (again PHP 7.0+):
By the way, this function constructor of a Closure doesn’t have the first class callable semantics as function is not scope sensitive, it has the scope bound:
Luckily PHP 7.0 brought in more consistent function calling and method invocation syntax and we don’t need to write out call_user_func() any longer.
Not even for call_user_func('get_object_vars', $this) thanks to PHP 8.1 first class callable syntax in shis short form: get_object_vars(…)->__invoke($this).
wish to invite you on a captivating sojourn into the sophisticated sphere of Desugaring. In the lexicon of programming, Desugaring denotes the elegant procedure of translating more ornate linguistic constructs—dubbed as Syntactic Sugar — into their simpler, fundamental equivalents.
Language processors, including compilers and static analyzers, often expand sugared constructs into their more verbose equivalents before processing, a process sometimes called “desugaring”.
“it could be exposed to societal prejudices and harmful stereotypes and integrate these into its images” (Craiyon)
Let’s delve into this with a trifecta of illuminating illustrations:
Java 8: Lambda expressions—an epitome of chic in Java 8. They are nothing short of syntactic sugar elegantly draped over the structure of functional interfaces.
Runnable r = () -> System.out.println("Executing with élan in Java!");
r.run();
Manifests as:
Runnable r = new Runnable(){
public void run(){
System.out.println("Executing with élan in Java!");
}
};
r.run();
PHP Syntactic Sugar Illustration (Craiyon)
Python: Drawing our gaze to Python, we find the list comprehension—a charming vignette of syntactic sugar.
elegantlist = [x**2 for x in range(5)]
Transforms to:
elegantlist = []
for x in range(5):
elegantlist.append(x**2)
Go: In the realm of Go, short variable declarations are a sublime manifestation of syntactic sugar.
func main() {
g := 42
fmt.Println(g)
}
Becomes:
func main() {
var g int
g = 42
fmt.Println(g)
}
The eyes, its always the eyes. Affirmative, Dave. I read you. (Craiyon)
Meandering onto our home turf, PHP 8.0, we encounter Constructor Property Promotions—an exhibition of syntactic sugar par excellence:
class Vertex {
public function __construct(
public float $x = 0.0,
public float $y = 0.0,
public float $z = 0.0,
) {}
}
Unveils as:
class Vertex {
public float $x;
public float $y;
public float $z;
public function __construct(
float $x = 0.0,
float $y = 0.0,
float $z = 0.0,
) {
$this->x = $x;
$this->y = $y;
$this->z = $z;
}
}
Venting through the protocol:
( new class (Vertex::class) { public function __construct(string $_) { var_dump ([
// :: show instance without a call to contructor :: //
($_ = new ReflectionClass($_))->newInstanceWithoutConstructor(),
// :: show default values :: ................... :: //
...array_map(fn ($_) => [$_->getName() => $_->getDefaultValue()], $_->getProperties())
]) ; } } );
Our programming languages—true art maestros—deftly handle the canvas of syntactic sugar, providing us, fortunate souls, with a more expressive, palatable syntax.
Image motives based on a visual excerpt from a TV series episode named “git gone” which is also the imaginary product name, the further text reads “kills bugs on contact” on the spray can label.
So there was this one question on Stackoverflow in which the OP was linking an .htaccess tester for Mod-Rewrite-Rules. Despite this being all fine I was asking myself what about really(tm) testing this?
So I remembered the rewrite-log from the days ago and thought: Why not just fire up a docker container, do the setup for testing rewrites by turning the logs to screaming and give it a drive.
But all the setup.
So I had an idea: What about you put the whole example into the Dockerfile? It has the RUN directive, so the moment the image builds it is actually executing it.
Having it exit non-zero even prevents of storing the image locally.
Ah yeah, and why actually write a Dockerfile even.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Even though parallel linting is fine, when the code-base is growing larger and larger, the build becomes slower and slower. A slow build sucks.
Git to the Rescue
One easy way to speed things up again is by reducing the number of files. So instead of linting all PHP files in directories, only linting the files that recently changed is a power-up.
For example if working with topic branches (e.g. bug-fixes or features) and having a main branch where changes are normally merged in (e.g. develop or master) the list of files to lint can be generated by listing all file-names changed (modified, added, deleted, …) between HEAD and the target branch (e.g. develop or master).
Let’s consider working on a topic-branch while having it checked out (HEAD) and the target branch is develop.
The output is not yet totally useful. First of all it contains empty lines but also deleted files. And it contains all files, when the change log was edited it will be also listed next to the php files interested for linting. And as this can span easily over multiple commits, files can be duplicated.
The answer to that are filters in the shell.
Streams all the Way Down
The first filter is to reduce the list already by file extension. Here is a filter w/ sed letting only pass .php and .phtml files:
Last but not least only existing files (not the deleted ones) must be passed to PHP for linting as otherwise it would rightfully error out.
I had to crack a bit on this one as in my mindset there is a lot of find when it is about finding files, but this time there is no find. What I came up with is ls as it does no output (just errors) when a file (or directory) does not exists. With xargs it is easy to provide multiple arguments to ls at once so that there is not so much to spawn.
This ensures to only list existing files, one per line, and the error output goes to /dev/null. So the full filter first removes any files of unfitting type (sed), any duplicates (sort) and non-existing files (xargs, ls):
sed -n '/\.ph\(p\|tml\)$/p' \
| sort -u | xargs ls -f1 -- 2>/dev/null
This then only needs to get wired up to the existing parallel lint command which is xargs to do the parallelism, php for linting and grep to detect any error (see as well the older blogpost).
But before taking a look at the command as a whole, as this is not so much about having it run far away like on Travis CI last time, let’s consider that not all changes are yet staged nor committed. So next to listing the files changed since branching from develop, there are also all the files currently dealing with:
Just a post about some of the sed lines I find scattered, to be extend in future edits.
Merge same Lines Together
$ sed '/^ \*$/{h;d};{H;s/.*//;x;s/^\n//}'
This sed example merges all “ *” lines that follow each other (e.g. empty lines in a class level Docblock comment in a PHP file). The pattern can be replaced with any pattern to describe the lines to merge together.
It copies each matching line into the hold buffer and drops the line.
On any other non matching line, the line is appended to the hold buffer, the read buffer emptied and exchanged w/ the hold buffer (clearing the hold buffer), any starting newline removed from the pattern space (as appending to an empty hod buffer would have created it but it’s unwanted).
Limitations: Won’t work when line pattern matches the last line / GNU sed
Indent all but first line
$ | sed '1{p;d}; s/^/ /'
1 applies to first line only, p prints and d deletes so there is no continuation to the second expression in which s searches for ^ start of line to replace it with two spaces. ; separates expressions, { and } group them.
Disable work-space up/down movers which block key bindings I use in Phpstorm. Important with that is that I don’t use these dynamic work-spaces at all, so making them static and only one:
Images motive based on a visual excerpt from a TV series episode named “git gone” which is also the imaginary product name, the further text reads “kills bugs on contact” on the spray can label.
Update: Turns out I was too eager to get the command line running. While it’s fine to have it perhaps for some systems, it is actually the case that Dbeaver has both a Debian repository and an Unbuntu PPA as I just learned:
It’s all on the download page [2] and all you need is to have the patience to scroll down (or Ctrl+F).
Highly recommended as there are updates often, it’s perhaps worth to schedule the downloads in the background as the repository can be slow.
I recently started to use Dbeaver [1] on my Ubuntu system. It gets updated quite seriously and luckily there are releases with .deb packages, so the package manager can install and update them. And there is an URL redirecting always to the lastest version.
So her is my current state of the one-liner to run the upgrade when I get noticed:
Standard disclaimers apply, verify checksums and the yadda yadda, otherwise, you know, install as root from the internet has never let you down than once.
Recently while in the mood I decided to upgrade my Thinkpad X280 from Ubuntu 16.04 LTS (for which it had the approval) to more current Ubuntu 18.04 LTS.
That also meant that I’m back on Gnome Shell which I’m not really a fan of, I was able to get my hands dirty on it when I was using Fedora a lot and it was new (“Gnome 3”) and well, I found it a bit rough.
However for the UI now – that is some years later – as it has been tailored for the Ubuntu flavor I find it quite acceptable (not because of Ubuntu but just the package is fine). I merely had some issues with the Laptop on Ubuntu 18.04 which most likely are not exactly related to Ubuntu 18.04 in specific, I’d like to write down about in this blog post:
ThinkPad Pro Docking Station with ThinkPad X280 on Ubuntu 18.04
First of all with the Lenovo ThinkPad Pro Docking Station (the USB-C one where you put the Laptop into and the USB-C docks from the left) I have in use there were some problems with my USB Keyboard on the docking station – it was just not enabled. This can be checked if it has a Num Lock LED and pressing Num Lock should toggle the light on and off. If you’ve got a keyboard with Num Lock LED at least in desktop mode this is a good check, while booting this is no check at all because there is no Num Lock LED going on, at least not for me. Apart from input devices via USB (I only have input devices on the dock at boot time normally) everything else worked with the docking station out of the box: Video via VGA port and Ethernet adapter.
It took me quite some time until I learned about having some BIOS settings influencing USB connectivity at boot time. Right now it works since some days in an acceptable manner (boot within dock and outside, suspend, take out, use out, suspend, put in etc.) and two BIOS settings I could identify I need to have for this working:
Config / Thunderbolt (TM) 3 / Security Level: “No Security” (while having the Thunderbolt(TM) device “Disabled” for support in Pre Boot Environment)
Config / USB / USB UEFI Bios Suppport: “Enabled”
As it was quite a bit of change here change there, this is perhaps not all settings, but I was using these. There is a warning to not enable a specific Linux one (which I had enabled to try it but disabled it quickly again as it is reported to brick Thinkpads on change (!)) and quite some users are reporting problems with the docking station regarding video which never was an issue for me from the beginning.
From my subjective impression, it was more an out-of-the-box experience while on Ubuntu 16.04, but it might be just since I upgraded the OS I perhaps wanted to finally get this into order, so this might be useful regardless of which Ubuntu version (or the underlying Kernel version).
Hunting the Keyboard Shortcut in the Dconf
While it was not enough to have actual keyboard connectivity problems (which really suck as the X280 has only one USB port left for use when in the dock, so I could only have mouse or keyboard working) with the Ubuntu upgrade to 18.04 I even “lost” one of the main keyboard shortcuts you have in browsers / editors / programming: CTRL+F to find in page / document / editor.
Finally I found a way to trouble-shoot this quickly, it works for any system that supports the dconf utility. With dconf dump it is possible to search for keyboard shortcut sequences, in my case CTRL+F is a “f” there, it can be quickly (and case independently) searched for:
Finally I could locate the culprit. Finding out under which configuration path needs a sed filter with a little “program” (examples of case insensitivity and hold buffer):
$ dconf dump / | sed -n '/^\[.*\]$/h;/f/I{x;p;x;p}'
[org/gnome/desktop/wm/keybindings]
move-to-workspace-9=['f']
It then shows the path to the setting above the match. The rest was merely straight forward to edit out that keyboard shortcut which I have no idea at all how it ended in there:
I don’t know how I was finally able to check that one, I actually was trying out the Ubuntu Keyboard Shortcuts Troubleshooting guide in the Wiki which made a good impression to me as it allowed me to check if/what is actually working with my keyboard, however it’s more on the event level which turned out working for me. And then I needed to look further and with one of many shattered Stackoverflow postings, eventually another time the hint on Dconf Editor and that it has Keyboard Shortcut configuration “somewhere there” did let me fiddle with searching within the shell.
In my opinion a recommended utility to install on Ubuntu 18.04 LTS when using the Gnome Shell for sure is “gnome-tweaks” also known as Tweaks or Gnome Tweaks Tool.
Enable the nightly rust release for the ripgrep project: rustup override set nightly
Compile: ./compile
The new binary can be found run from ./target/release/rg
Shell installer are quite fishy, so this is not the preferred way of installation, there is also the possibility to directly install it via (packaged) cargo command (cargo install ripgrep) but that version is w/o AVX/SIMD as both can not compile (currently) with the stable Rust version.
While it was not much advised to use assertions (the assert PHP language construct) prior to PHP 7 due to the fact that it actually eval’ed a string’ed code, these days are gone. This is probably a lesser known fact with all the other immense improvements PHP 7 and 7.1 came with, so I’d like to take the opportunity with this post to highlight the PHP assertion feature that comes with zero run-time overhead and zero side-effects for production code. Continue reading →
When it comes to nicely performing PHP scripts (yes in PHP these are all scripts as PHP code is run-time) there is a nice addition since PHP 7 named the Null coalescing operator which plays very well with the basic nature that PHP is loosely typed and unset variables are basically null when warnings are not in effect. You know what? Not set warnings (like with isset) are not in effect with the ?? Null Coalescing Operator (PHP Manual).
So how about a simple and quick usage example for lazy-loading? By default all class members are null when defined:
With any new MyFoo() that private property will be null. Now one thing could be to properly inject the Config in the constructor (__construct()) but while you’re writing code you might want to defer the details to later (dependency injection is not always useful but don’t get me wrong it’s generally the option to go on with constructor injection while you progress) one way to deal with the outcome is lazy loading (back to constructor injection, you might want to inject a ConfigFactory then).
So what is about lazy loading here? Let’s say MyFoo is used more centrally in an application (a primitive) so might be some kind of service to your application, you only want to instantiate the Config in case it is actually used. You know that it is used when it is acquired from the service-like-acting MyFoo when the getter is called (mind the Law od Demeter and Getters and Setters can be a smell, too):
class MyFoo
{
...
public function getConfig(): Config {
return $this->config;
}
}
Now when that getConfig() method is called, it will return null unless the Config has been set to private MyFoo::$config so far – which is not a case in our scenario. Also the Config of MyFoo is a singleton (not the (anti-) pattern) , so it is easy to implement it on the go:
class MyFoo
{
...
public function getConfig(): Config {
return $this->config ?? $this->config = new Config();
}
}
Creating the Config object is here deferred to the point when getConfig() is called the first time. That is also the first time it is needed (by definition of this simplified example at least). The Null Coalescing Operator is helpful here to do this in a single line.
It is also easy to switch to constructor injection (eager loading) or even constructor injection based lazy loading when you inject a factory that will create (or a repository that providea) the Configat that time in place.
I hope this is a nice example to show how well the Null Coalescing Operator in PHP plays with non-initialized object properties (or even unset variables). Which reminds me I should not use it too often.
class MyFoo
{
...
public function getConfig(): Config {
return $this->config ??= new Config();
}
}
The only thing missed for ?? addicts like me might be the sometimes unnecessary operand after the operator:
$var = $unset ??; # expressing just null
This will spare isset()if conditionals but might also direct dealing with nulls to other places (which can add a lot of burden to consumers). But I’m just too little experienced in writing PHP wiki RFCs and I couldn’t even provide a patch, so with closing time for PHP 7.2 this is really future material (and perhaps just a sign I want “wrong” things).
This is from the shock your co-worker department: There is an easy one-liner to make any composer based project spit “Segmentation fault (core dumped)” regardless of the Composer command entered: Continue reading →
Now with the newborn elefant PHP 7 in the herd, there is a lift on the date timezone settings warning: it has just been removed. That means, it’s now that you need to take care in the server’s configuration that the proper default timezone value is set, otherwise it will fall-back to UTC with no more reminder spamming the log-files or screen. Alternatively, you can make use of the date_default_timezone_set() function within your application to configure the default value.
With PHP 7 around the corner here is a small tip how you can at least lint the code in your project to be PHP 7 syntax compatible. That allows you to easier obtain forward-compatible PHP code with ease. So if you already integrate with Travis, all you need to do is to add some two-to-four lines to your .travis.yaml file and you’re done. Here is how: Continue reading →
PHP’s Simplexml ships with a lot of magic to simplify access to an XML documents element and attribute node values. Some criticize this and suggest to use the DOM library instead. The DOM library on the other hand, even it can do everything tend to be known with an XML document, it’s pretty verbose – and yes that’s some critique with XML as well, the verbosity. Sure there are many nice libraries around the DOM library and wrapping it and one of these libraries again is Simplexml.
From a data-type perspective, the SimpleXMLElement is quite an interesting one actually, literally I mean figuratively -what not. It’s something like a hierarchical data-structure. One that comes with it’s own query method via the xpath() method. It can be iterated, traversed, nodes added and leafs unset as if it would be an array or an std class. And it comes with a serializer built in – into XML – in both directions.
From it’s internals, it’s fully backed from C code below from libxml, it’s also pretty fast and perhaps also fine with the memory (at least I hope).
It speaks Unicode in the popular UTF-8 encoding you know from the web and if you need to, it can even convert to other encodings.
And one of it’s magic properties is that it’s such a class of classes in PHP that can be casted from one class to another. This works by converting one (subclass of a) SimpleXMLElement to another subclass of it by sending it through DOM (the besaid sister-library):
This is actually not only true for SimpleXMLElement but also to the node-classes in a DOMDocument to a certain degree but this post is about SimpleXMLElement so just saying.
I have to say it: With so much simplification and magic, there is a price to pay and there are limitations, too. The constructor is final, so you can’t override it. No way :). This hinders you in terms of “classic” object inheritance. One path out is to decorate the elements, but even I did this in the past, it doesn’t feel equally well as well. It might also be more work as first thought. But most often, extending SimpleXMLElement just more to sugar-in some methods, so it’s often not worth for a full-feature decoration. So this is a limitation. ERR_TOO_MUCH_MAGIC comes to mind.
And some argue as for the data-structure you can’t use it as array or object store as all class-properties or array-indexes represent either XML element or attribute nodes only accepting scalar types (actually stringy values).
Storing Arrays and Objects in a SimpleXMLElement
Let me elaborate on that last point a little. It’s normally not possible to store array or object data inside a SimpleXMLElement. As you couldn’t serialize it as XML, by default it’s fordidden to do:
class Foo extends SimpleXMLElement
{
}
$foo = new Foo("<doc/>");
# Warning: It is not yet possible to assign complex types to properties
$foo->bar = $foo;
If you now think that creating a private field and assigning the data to the private field would be a solution, it will teach you about another limitation: there are no private fields with a SimpleXMLElement. It’s field are all exposed XML nodes so all you can store there are strings.
But wouldn’t it be nice to actually be able to store some objects therein? Let’s elaborate a bit on the internals which is how I discovered some nice properties of the document model in PHP and it’s use from within Simplexml.
The SimpleXMLElement is somewhat a shell around some other object only. It perhaps can be describben as a Flyweight (as in the pattern), an interface of factory and object manager of the underlying document nodes. And the document again can be represented as a DOMNode which again is a shell/interface around the underlying document node managed by libxml. This is the underlying structure of not only the SimpleXMLElements but also the tree structure of the DOM. The PHP SimpleXML/DOM extensions manage all these document nodes nicely for us.
If it is now possible to turn a SimpleXMLElement into a DOMNode it is then – because of the object model in PHP with the dynamic properties (every object in PHP is actually somewhat an array/hash) – possible to assing data to a document node without creating a new element as it would be the case on level of SimpleXMLElement:
class Foo extends SimpleXMLElement
{
function setData($data) {
$element = dom_import_simplexml($this);
$element->data = $data;
}
}
$foo = new Foo("<doc/>");
$foo->addChild('bar')->setData($foo);
This does actually work, but the data won’t yet persist. What is necessary to keep the dynamic property data here in memory within the DOM is to add as circular reference to the DOMNode, let’s call that one circref in this example. It’s then possible to write and read the data:
The usage example demonstrates that it is now possible to store (or attach) an object to the document node accessed via Simplexml:
$foo = new Foo("<doc/>");
$foo->addChild('bar')->setData($foo);
var_dump($foo->bar->getData());
# class Foo#1 (1) {
# public $bar =>
# class Foo#2 (0) {
# }
# }
For those who hate Simplexml but even read until here: As already written earlier, this same principle works with pure DOMDocument / DOMNode as well. Just in case you want to re-use the node based data-structure and you need to add (object) information to it. All you need is the circular reference to keep the association between the data and the node in memory. And it’s really within the same document:
# obtaining the data via DOMDocument
$doc = dom_import_simplexml($foo)->ownerDocument;
$bar = $doc->getElementsByTagName('bar')->item(0);
var_dump($bar->data);
As you can imagine same applies for xpath queries – both via DOMXPath or SimpleXMLElement.
Hakre's devlog, thoughts and rants on wordpress on wordpress.com. And webdesign related. And web development related. My weapons of choice are Netscape 2.01, HTML, CSS, PHP and the Gif Construction Kit.
Defective by Design - HTML5 is so awesome you can screw it now. Congratulations. Tell W3C: We don't want the Hollyweb! - Get educated and spread the word!
Issue 2.1 is out! (; as print version so far, not yet on the website.) Take a look at conferences and events to get as well all back issues of Libre Graphics magazine with a discount or just order online.