1

PHP allows you to increment strings. Why?

Let's jump ahead a bit. Take the following code:

$string = '9ZzZ';
echo ++$string; // 10AaA

From a purist point of view this may seem like nonsense, however, you can see there is clearly a pattern here. Each column is treated as a set, (numbers, uppercase letters, lowercase letters). Then each set behaves like its own numbering system.

The manual confirms this and states that they copied Perl:

PHP follows Perl's convention when dealing with arithmetic operations on character variables and not C's. For example, in PHP and Perl $a = 'Z'; $a++; turns $a into 'AA', while in C a = 'Z'; a++; turns a into '[' (ASCII value of 'Z' is 90, ASCII value of '[' is 91). Note that character variables can be incremented but not decremented and even so only plain ASCII alphabets and digits (a-z, A-Z and 0-9) are supported. Incrementing/decrementing other character variables has no effect, the original string is unchanged.

But, it doesn't actually explain why.

Perls manual states something very similar, but again goes in to no explanation as to why this extra magic was added.

The auto-increment operator has a little extra builtin magic to it. If you increment a variable that is numeric, or that has ever been used in a numeric context, you get a normal increment. If, however, the variable has been used in only string contexts since it was set, and has a value that is not the empty string and matches the pattern /^[a-zA-Z][0-9]\z/ , the increment is done as a string, preserving each character within its range, with carry

Similarly enigmatically:

The auto-decrement operator is not magical.

Why is increment so important but decrement isn't? And why would they do this at all?

It's logical in its own way, and I can see uses for it (though you could write something more obvious in its place). I can even see why they didn't to mill through the ASCII character set (since that might not be the character set your using) or through the character set defined in php.ini as that could significantly alter behaviour between systems. So why bother at all?

  • 1
    Aside, that bit about the pattern is important in perl. If it starts out with a digit, its a numeric thing rather than a string thing so that 3d8 when incremented becomes 4 (ideone.com/Yoon3l). Php doesn't have that restriction or the concept of a numbery thing vs a stringy thing. This means that the two types overlap to some o_O moments. ideone.com/ppfv3f – user40980 Oct 20 '15 at 15:48
4

My understanding is that the feature was originally intended for generating sequences of filenames for scripts that need to produce variable numbers of output files. While you could use a simple counter for the purpose, this hasa few drawbacks (unpredictable name length causes bad sorting when files are listed alphabetically; letters are preferable to digits when many files are needed in order to keep generated names short), both of which can be solved by initialising your counter to (for example) 'aaaa'.

While other solutions are clearly possible and arenot even especially hard, perl's solution is remarkably concise.

Why php copied the idea, I'm not sure. It was never really intended for the type of application that benefits from this. It perhaps has something to do with the fact that perl was the dominant language for web scripting at the time.

  • You may often save files (uploads, logs, etc) so this does make a weird sort of sense, but it's a solution to an incredibly specific problem integrated to a widely used feature (strings). It's so specific in fact, that in > 10 years of developing PHP (>4 full time), this is the first time I've run across it... Hmm, furthermore, I'd actually say (in the web world) this is a really bad solution, because of it's predictability. – DanielM Oct 20 '15 at 15:47
  • 1
    @DanielM it is a problem that perl, from the start, was designed to address back in very early versions. Perl was in part intended to replace shell scripts and needed to be able to easily provide similar functionality. There are shell utilities that do this. Making it hard for a sysadmin to write the code in perl over shell would have made it less useful or adopted. Remember that perl is a language designed by a sysadmin for himself and shared to others. – user40980 Oct 20 '15 at 15:50
3

There is a really useful utility in the unix world for splitting up large files named (unsuprisingly) split.

Output pieces of FILE to PREFIXaa, PREFIXab, ...; default size is 1000 lines, and default PREFIX is 'x'.

You can see that incrementing of strings there.

Perl is especially useful in situations where one wants to pull out the swiss army chainsaw of the unix utility world. I have in the past used this functionality for writing my own tools that needed to have similar functionality as that provided by split. And 263 possible values in two characters is quite a bit more than 103.


As to why ++ is magical while -- isn't? Its because it is easy to identify a consistent expectation for what ++ on a string does on boundary conditions while -- doesn't have easy expectations.

$foo = "zz";
$foo++;
print "$foo\n";

This is aaa. Very similar to how one would expect the following to behave:

$foo = 99;
$foo++;
print "$foo\n";

And while:

$foo = 0;
$foo--;
print "$foo\n";

gives you -1, would should:

$foo = "a";
$foo--;
print "$foo\n";

return? And with that, the designer throws up his arms and says "you know what, there's not a use case for it and I can't make it work consistently that isn't surprising to the programmer." and says instead "it isn't magical" and leaves it at that.

  • Actually what to do with a is easy, logically it's -b, since we're dealing with base 26 where a ~ 0, b ~ 1. Though that does look odd. Additionally, you'd need to "remember the columns so 1a-- becomes 0a, otherwise repeated use of ++ and -- would not result in the same "numbers". And while the filename thing makes perfect sense, the fact that it runs over zzz -> aaaa kinda makes the whole thing a bit less useful, because your new filename proceeds all the old ones, so you'd have to plan for that case anyway. I think usage makes sense, inclusion as a feature does not. :/ – DanielM Oct 20 '15 at 15:55
  • @DanielM In perl, "1a"-- is a scalar to be interpreted as a number and would be 0. I contend that php misimplemneted this functionality and leads to surprising results even with ++. The simple answer remains - that as a sysadmin, I have used it. Perl as a sysadmin language existed long before the web a scribbling on a blackboard. That someone doesn't use a language feature in perl isn't surprising - I haven't used all the blades on a swiss army knife either. (and I haven't yet produced 17k different file names; 1k yes... but not 17k). – user40980 Oct 20 '15 at 16:01
  • In PHP "1a" is not a number so the underlying part is already different. Perhaps because of this, they've have implemented it differently, why do you feel they've "misimplemented" it? Also, just because you can't imagine overrunning a buffer doesn't mean you shouldn't plan for it. I'm hoping I can retire before 2038 specifically because people didn't. :) – DanielM Oct 20 '15 at 16:12
  • 1
    @DanielM because in php "3d9"++ is "3e0" and "3e0"++ is 4. ideone.com/ppfv3f – user40980 Oct 20 '15 at 16:13
  • 1
    3v4l.org/Z3eOH ... That is disgusting. – DanielM Oct 20 '15 at 16:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.