

Three string functions every PHP project needs - martian
http://engineering.thumbtack.com/2011/05/20/three-string-functions-every-php-project-needs/

======
Jach
One caveat: until the mythical PHP 6 comes out, if you're using unicode at all
you should be using the multibyte string functions.
<http://www.php.net/manual/en/ref.mbstring.php> Python has had unicode support
for a while and generally does the right thing, something that might be missed
with blind PHP replication.

------
Nycto
For anyone interested, you can actually make the startsWith and endsWith
methods a lot faster by using strncasecmp or substr, like this:

[https://github.com/Nycto/Round-
Eights/blob/master/src/functi...](https://github.com/Nycto/Round-
Eights/blob/master/src/functions/strings.php#L319)

It could be a micro-optimization, but I find myself using these methods quite
and it's a simple tweak to make.

~~~
birken
The string slicing would have been a lot more efficient had PHP accepted my
patch to add this into the PHP core functions :) -->
<http://bugs.php.net/bug.php?id=54387>

In general though we just use these around the code base for general use, and
efficiency isn't a concern.

------
nikz
May be slightly off-topic, but I feel a little pain behind my eyes whenever I
see the hack-around-namespaces function naming (e.g tt_whatever, for
"ThumbTack" presumably).

Surely a singleton class would be a nicer way to do this (or just leave the
"tt_" off, why is it necessary, you're not overriding core functions)?

~~~
birken
We actually had a debate in our engineering dept about how we wanted to handle
functions like this, and in the end decided on tt_function_name() in the
global function space.

We decided against putting them in explicit namespaces, because we felt these
were convenience functions and they should be convenient to use. We felt the
convenience of:

if (tt_str_startswith($url, '<https://)>) { }

over something like:

if (tt/global/string/starts_with($url, '<https://)>) { }

was worth the lack of organization. We have <10 of these types of global
functions in our code base and we are very careful about adding new ones. All
other classes and functions are either in a namespace or class context.

We went with the tt_ prefix because we wanted to cover our bases and really
explicitly ensure we never will collide with a PHP function, and we felt it
isn't too unwieldy.

As for using a singleton class, since 5.3 we prefer to use namespaces instead.

~~~
wvenable
Isn't this what _use_ is for?

    
    
        use tt\global\string;
        if (string\starts_with($url, 'https://)) { }

~~~
birken
Sure is, and we do organize our 'use' statements the same way one would
organize 'import' statements in a python file.

However in this context again we felt that the convenience of just being able
to throw these functions in place without having to worry about putting the
proper use statement was worth the tradeoff.

------
benologist
I love StartsWith, EndsWith and also Contains in C#. Contains especially feels
so nice to use compared to IndexOf all the time.

~~~
michaelcampbell
Indeed. As a Java guy, I was a bit surprised ruby's default library didn't
have them (when I started with ruby, anyway; way pre-rails; it might now).
Trivial to implement, but still.

------
dstein
In JavaScript I always use:

    
    
      String.prototype.startsWith = function(s) {
        return this.substring(0,s.length)===s;
      };
      String.prototype.endsWith = function(s) {
        return this.substring(this.length-s.length)===s;
      };

~~~
rudiger
What's the current consensus on augmentation of built-in prototypes [1]? Is it
still a contentious issue?

[1] [http://michaux.ca/articles/javascript-the-good-parts-
built-i...](http://michaux.ca/articles/javascript-the-good-parts-built-in-
object-augmentation-and-namespacing)

~~~
kemayo
Object.prototype aside, I think it's a bad habit in any sort of large-ish
system. Partially because of namespacing concerns; if prototype-extension
happens in libraries you use, you might have common things like "startsWith"
clobber each other with subtle incompatibilities.

There's also visibility concerns. If you add random methods to things that
look like language primitives it can be hard to get an overview of where
they're really being used.

Anecdotally, I had to go through and remove all use of prototype.js from
deviantART because we decided to standardize on jQuery. It was a pain. A
serious, serious pain. Because prototype.js extended Array, String, and other
objects. So I had to go make a list of every single method that prototype.js
added to these, and find all incidences of those somewhat-common strings in
our codebase and examine them case-by-case to see if they were actually
calling the prototype.js versions.

By contrast, if I'd wanted to remove all use of jQuery I could have built an
unambiguous list of all uses with a fairly simple grep.

------
lox
What exactly does this do that isn't implemented with substr already? Have I
misread the docs? Seems it handles positive and negative offsets.

Also, wouldn't startsWith and endsWith also be already implemented as strpos
and strrpos?

Don't get me wrong, none of those functions are particularly elegant, but at
least they are the "PHP way".

------
wccrawford
I was just wishing I had 'startswith' the other day again in PHP. Not that I
can't write it myself, but I just really hate to create global functions like
that... Simple things like that should already exist.

------
henning
Those functions are implemented inefficiently and they're ugly. How is this
worthy of a blog post or a submission?

~~~
birken
Why do you think they are ugly?

------
kleiba
I don't know PHP, but does the slice function work when $end > $start +
$length?

