Well we know that in Javascript string can be handled as object in a way like this:

text = new String("This is a test string.");

This feature is unavailable in PHP, which is somewhat unfortunate seeing how PHP even adds object-oriented supports for Datetime. Nonetheless I've just come across a string class made by someone called Michael Scribellito, the script looks like it can be used by anyone. The code is:

<?php

/*
 * String Class
 *
 * Allows Strings to be handled as objects.
 *
 * @author  Michael Scribellito
 * @link    http://mscribellito.com
 */

final class String {

// holds the value of the String object
private $value;

public function __construct($value = '') {

    $this->value = (string) $value;

}

public function charAt($index) {

    if (abs($index) >= $this->length()) {
        throw new Exception('Index out of bounds');
    }

    return substr($this->value, $index, 1);

}

public function charCodeAt($index) {

    if (abs($index) >= $this->length()) {
        throw new Exception('Index out of bounds');
    }

    return ord($this->charAt($index));

}


public function compareTo($that) {

    if (!($that instanceof String)) {
        $that = new String($that);
    }
    return strcmp($this->value, $that->value);

}


public function compareToIgnoreCase($that) {

    if (!($that instanceof String)) {
        $that = new String($that);
    }
    return strcmp($this->toLowerCase()->value, $that->toLowerCase()->value);

}

public function concat() {

    $strs = func_get_args();
    $temp = array();
    foreach ($strs as $str) {
        if (!($str instanceof String)) {
            $str = new String($str);
        }
        $temp[] = $str->value;
    }
    return new String($this->value . implode('', $temp));

}

public function contains($sequence) {

    return $this->indexOf($sequence) >= 0 ? TRUE : FALSE;

}


public function endsWith($suffix) {

    return preg_match('/' . preg_quote($suffix) . '$/', $this->value);

}

public function equals($that) {

    if (!($that instanceof String)) {
        $that = new String($that);
    }
    return $this->value === $that->value;

}

public function equalsIgnoreCase($that) {

    if (!($that instanceof String)) {
        $that = new String($that);
    }
    return $this->toLowerCase()->value === $that->toLowerCase()->value;

}

public static function fromCharCode() {

    $args = func_get_args();
    $str = new String();
    foreach ($args as $arg) {
        $str = $str->concat(chr($arg));
    }
    return $str->value;

}

public function hashCode() {

    $h = 0;
    for ($i = 0, $l = $this->length(); $i < $l; $i++) {
        $h = 31 * $h + ord($this->charAt($i));
    }
    return $h;

}

public function indexOf($substring, $fromIndex = 0) {

    if ($fromIndex >= $this->length() || $fromIndex < 0) {
        throw new Exception('Index out of bounds');
    }

    $index = strpos($this->value, $substring, $fromIndex);
    return (is_int($index)) ? $index : -1;

}

public function isEmpty() {

    return $this->length() === 0 ? TRUE : FALSE;

}

public function lastIndexOf($substring, $fromIndex = 0) {

    if ($fromIndex >= $this->length() || $fromIndex < 0) {
        throw new Exception('Index out of bounds');
    }

    $index = strrpos($this->value, $substring, $fromIndex);
    return is_int($index) ? $index : -1;

}


public function length() {

    return strlen($this->value);

}

public function matches($pattern) {

    return preg_match($pattern, $this->value);

}

public function md5() {

    return new String(md5($this->value));

}

public function quote() {

    return new String('"' . $this->value . '"');

}

public function replace($old, $new, $count = NULL) {

    if ($count !== NULL) {
        $temp = str_replace($old, $new, $this->value, $count);
    } else {
        $temp = str_replace($old, $new, $this->value);
    }
    return new String($temp);

}

public function replaceAll($pattern, $replacement) {

    $temp = preg_replace($pattern, $replacement, $this->value);
    return new String($temp);

}

public function replaceFirst($pattern, $replacement) {

    $temp = preg_replace($pattern, $replacement, $this->value, 1);
    return new String($temp);

}

public function sha1() {

    return new String(sha1($this->value));

}

public function split($pattern, $limit = NULL) {

    return preg_split($pattern, $this->value, $limit);

}

/*
 * Tests if this String starts with the specified prefix.
 *
 * @access  public
 * @param   string
 * @return  boolean
 */

public function startsWith($prefix) {

    return preg_match('/^' . preg_quote($prefix) . '/', $this->value);

}

/*
 * Returns a new String that is a substring of this string.
 *
 * @access  public
 * @param   int
 * @param   int
 * @return  String
 */

public function substring($start, $length = NULL) {

    if ($length !== NULL) {
        $temp = substr($this->value, $start, $length);
    } else {
        $temp = substr($this->value, $start);
    }
    return new String($temp);

}

/*
 * Converts this String to an array of characters.
 *
 * @access  public
 * @return  array
 */

public function toCharArray() {

    $chars = array();
    for ($i = 0, $l = $this->length(); $i < $l; $i++) {
        $chars[] = $this->charAt($i);
    }
    return $chars;

}

/*
 * Converts all of the characters in this String to lower case.
 *
 * @access  public
 * @return  String
 */

public function toLowerCase() {

    return new String(strtolower($this->value));

}

/*
 * Converts all of the characters in this String to upper case.
 *
 * @access  public
 * @return  String
 */

public function toUpperCase() {

    return new String(strtoupper($this->value));

}

/*
 * Removes leading and trailing whitespace.
 *
 * @access  public
 * @return  String
 */

public function trim() {

    $temp = preg_replace('/^\s+/', '', preg_replace('/\s+$/', '', $this->value));
    return new String($temp);

}

/*
 * Removes leading whitespace.
 *
 * @access  public
 * @return  String
 */

public function trimLeft() {

    $temp = preg_replace('/^\s+/', '', $this->value);
    return new String($temp);

}

/*
 * Removes trailing whitespace.
 *
 * @access  public
 * @return  String
 */

public function trimRight() {

    $temp = preg_replace('/\s+$/', '', $this->value);
    return new String($temp);

}

/*
 * Returns the value of this String
 *
 * @access  public
 * @return  string
 */

public function __toString() {

    return $this->value;

}

}

Perhaps there are still some new methods that can be added to this class, but it does seem to provide a way for strings to be handled like objects. The question is, would you recommend using PHP string in object-oriented way? Just curious.

    I didn't read through it in detail, but unless you can show me something I can do with that String object I can't already do with "normal" strings in PHP, I can't personally think of why I'd want to use it. (Maybe I'm just not object-oriented enough? 😉 )

      umm the only exclusive feature it has compared to procedural string usage is that the content inside a string is a private property. It can only be accessed using a getter method, in this case it is the __toString() method. Not sure what you think though. I do believe that more methods can be added to the string class to improve its usefulness.

        Doesn't seem to be any reason IMO to use a string as an object in php. But for comparison sake lets compare native strings vs. this class:

        <?php
        include('./classes/String.class.php');
        
        $string = 'Hello, I am a native string.';
        $string2 = 'I am a second native string.';
        
        $strObj = new String('Hello, I am a string object.');
        $strObj2 = new String('I am a second string object.');
        
        
        // charAt
        echo $string[5];
        echo $strObj->charAt(5);
        
        // charCodeAt
        echo ord($string[5]);
        echo $strObj->charCodeAt(5);
        
        // compare
        echo strcmp($string,$string2);
        echo $strObj->compare($strObj2);
        
        // case-insensitive compare
        echo strcasecmp($string,$string2);
        echo $strObj->compareToIgnoreCase($strObj2);
        
        // concat
        echo $string.$string2
        echo $strObj->concat($strObj2);

        Etc... Object takes more typing, so I'll stick with native 😛

          In javascript, string literals and string objects are different. in most cases, they can be handled the same, but there are subtle differences that can lead to hard-to-track problems.

          developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String wrote:

          code may break when it encounters String objects when it expects a primitive string instead

          Douglas Crockford also made some very compelling arguments against using the javascript String() object in one of his lectures, though I can't remember which one. Go watch all of them, it's worth it.

          Regarding this PHP version of String: honestly, I can't think of anything "useful" to add to a class like this that wouldn't be simpler with a normal string. Everything that this class does can be done quicker with normal string functions. (Maybe, if it did anything to address making its methods multibyte-aware, it might find some use...? )

          As it stands, however, it's just a lot of overhead; and it makes most of the things we normally do with strings a lot more complicated.

          [edit]

          Lord Yggdrasill wrote:

          It can only be accessed using a getter method, in this case it is the toString() method.


          ...which accomplishes what, exactly - besides making the string harder to edit?
          In fact, I'd argue that the only problem using
          toString (to return an actual string) solves is the fact that the object that represents a string isn't a string - and the author recognizes that if you couldn't at least pretend it was a string, it would be completely useless.

          Lord Yggdrasill wrote:

          I do believe that more methods can be added to the string class to improve its usefulness.

          maybe the object could be made more useful than it is, but I don't see how it could be made more useful than actual strings.

            traq wrote:
            Lord Yggdrasill wrote:

            I do believe that more methods can be added to the string class to improve its usefulness.

            maybe the object could be made more useful than it is, but I don't see how it could be made more useful than actual strings.

            To make it as useful as actual strings, you're looking at implementing these functions as methods. And that's ignoring the need to use the getter method to get access to its primitive string value if you want to use it for any other function that doesn't expect a String object.

            Lord Yggdrasill wrote:

            umm the only exclusive feature it has compared to procedural string usage is that the content inside a string is a private property. It can only be accessed using a getter method, in this case it is the __toString() method.

            Even if that were an exclusive feature (i.e., even if that were a feature not already possessed by native PHP strings), what exactly does that get you?

            I can see one justification for this, but this class doesn't address it, so it doesn't count (in which case it's not even one, is it?). A String could have its value modified in-place, and all subsequent references to the object would reflect the modified value. But no such modifications are possible in the class as written: the String is immutable - a feature of String objects in object-oriented languages like Java and C#. In other words, those other languages have String objects designed to make them behave the way PHP strings do natively.

              Weedpacket;11003959 wrote:

              I can see one justification for this, but this class doesn't address it, so it doesn't count (in which case it's not even one, is it?). A String could have its value modified in-place, and all subsequent references to the object would reflect the modified value. But no such modifications are possible in the class as written: the String is immutable - a feature of String objects in object-oriented languages like Java and C#. In other words, those other languages have String objects designed to make them behave the way PHP strings do natively.

              Interesting. I only have limited knowledge with C and completely unfamiliar with Java. Are you saying they have string objects too? If so, what functionalities do they have? I am definitely looking into an idea to make the string class more useful than the original, and if you can give me some advices and hints Id appreciate it very much.

                Weedpacket;11003959 wrote:

                To make it as useful as actual strings, you're looking at implementing these functions as methods.

                Indeed. And preferably, with the same names (so I don't have to spend time memorizing anything).
                And I still want it to be multibyte-aware before I even consider trying it out.

                Weedpacket;11003959 wrote:

                And that's ignoring the need to use the getter method to get access to its primitive string value if you want to use it for any other function that doesn't expect a String object.

                __toString should handle that just fine, actually. I can't think of a situation where it wouldn't work...?

                  Lord Yggdrasill wrote:

                  Interesting. I only have limited knowledge with C and completely unfamiliar with Java.

                  I said C# (more accurately, C&#9839; (more accurately, the .NET framework)), not C; completely different languages.

                  Yes, C# and Java have string objects - those are the only sorts of strings they have (not surprising, since they're object-oriented languages). C doesn't have strings at all except as a lexical convenience in source code; emulating C strings in PHP involves somewhat more work.

                  Java: java.lang.String (see also StringBuffer, StringBuilder, and the java.text package.

                  .NET: String (members); see also the System.Text namespace, including System.Text.StringBuilder.

                  if you can give me some advices and hints Id appreciate it very much.

                  Design your object hierarchies to reflect what you're actually working with. You'd only need to create a "String" class if you were trying to design a new or model an existing language/programming model/framework. And before you ask, there is already a .NET implementation of PHP.

                    I see, thanks for the reply. I'm still wondering about this though:

                    Weedpacket wrote:

                    A String could have its value modified in-place, and all subsequent references to the object would reflect the modified value.

                    A bit confused tbh. I tried to create this method but with no luck, will appreciate help and suggestions...

                      Lord Yggdrasill wrote:

                      I tried to create this method but with no luck, will appreciate help and suggestions...

                      public function setValue($string)
                      {
                        $this->value = (string)$string;
                      }

                      Of course, if you're going to write getters and/or setters for a value property you might as use the mechanisms provided (though personally I'd prefer something a bit closer to the way C# does it; cf. this RFC in the PHP Wiki).

                      In this case, the only thing that is achieved by not just making [font=monospace]$value[/font] public is that setting its value (at instantiation, or via the setter method above) forces a type cast. Which is kind of pointless because the only methods where it makes a difference are the two [font=monospace]equals[/font] methods; all of the functions which ever get to see [font=monospace]$value[/font] will happily do the cast themselves, so the type doesn't matter to them.

                      The reason why those two methods care is because of their use of [font=monospace]===[/font] instead of [font=monospace]==[/font] so that the types of their operands ([font=monospace]$this->value[/font] and [font=monospace]$that->value[/font]) are checked. But hold on: when will [font=monospace]$this->value[/font] and [font=monospace]$that->value[/font] ever have different types?

                        I see, so its simply a setter method with the functionality that checks the type of variables? I thought it'd be rather complicated that only advanced programmers can do. XD

                        And, well... In Javascript you can declare a string object in either one of the two ways:

                        // Approach 1:
                        text = "This is a string";
                        
                        // Approach 2:
                        text = new String("This is a string");
                        

                        And these two make no difference. This means that even if you use the first and standard approach(without using new keyword and parenthesis), the string text is still declared as an object. If you use methods for this string such as text.toUpperCase(), it will work out regardless of the approach you use. For this reason almost all javascript programs use the first approach for its simplicity.

                        In PHP, however, the two codes will be quite different:

                        // Approach 1:
                        $text = "This is a string";
                        
                        // Approach 2:
                        $text = new String("This is a string");
                        

                        And the first approach does not give you a string object, which is a problem. If you use $text->toUpperCase() for the first approach it will generate an error, while the second approach works flawlessly. I was wondering if theres a way for PHP to make a string into object with the first approach just like javascript. Please do lemme know if you have any ideas how to accomplish this. Thx.

                          Lord Yggdrasill wrote:

                          And the first approach does not give you a string object, which is a problem. If you use $text->toUpperCase() for the first approach it will generate an error, while the second approach works flawlessly.

                          Then just use strtoupper($text). You're contrasting syntactic sugar here.

                          Lord Yggdrasill wrote:

                          I was wondering if theres a way for PHP to make a string into object with the first approach just like javascript.

                          Conceptually, you can consider the string to be an object, though not an object of a class type (I think, or at least not of a class type with an interface that you have in mind). Syntactic sugar can be nice, but really, what is the point? Quoted for truth:

                          Weedpacket wrote:

                          Design your object hierarchies to reflect what you're actually working with. You'd only need to create a "String" class if you were trying to design a new or model an existing language/programming model/framework.

                          If you have more concrete goals than just trying to have syntactic sugar that mimics what you know of Javascript's string class interface, then that would be a starting point for a string class for PHP.

                            Lord Yggrdrasill wrote:

                            I see, so its simply a setter method with the functionality that checks the type of variables? I thought it'd be rather complicated that only advanced programmers can do. XD

                            It would be more complicated if the whole thing wasn't so trivial to begin with; if the object needed some sort of validation or canonicalisation when its properties' values are being set, then there would be something for the setter to do. As it is, the only thing the setter needs to do is make sure the value is set to a native PHP string; and as I said that's only because the equality methods check its type.

                            Lord Yggrdrasill wrote:

                            And these two make no difference.

                            So you didn't follow up traq's suggestion? (For another reference on the subject, see Mozilla's JavaScript reference, specifically Distinction between string primitives and String objects).

                              Weedpacket;11004051 wrote:

                              So you didn't follow up traq's suggestion? (For another reference on the subject, see Mozilla's JavaScript reference, specifically Distinction between string primitives and String objects).

                              Oh sorry about that, I was referring to the fact that it makes no difference when you use string methods such as string.toUpperCase() and string.toLowerCase(). But yeah, I realize there are minor distinctions between the two. Such distinctions, however, wont cause the script to fail if you use methods for a string declared in either way.

                              laserlight;11004048 wrote:

                              Then just use strtoupper($text). You're contrasting syntactic sugar here.

                              I know what you mean, But... The idea is to find how to use string in OO way, $string->toUpperCase() instead of strtoupper($string). I am not saying the procedural way wont work, just trying to seek for a better alternative.

                              laserlight;11004048 wrote:

                              If you have more concrete goals than just trying to have syntactic sugar that mimics what you know of Javascript's string class interface, then that would be a starting point for a string class for PHP.

                              Umm this sounds like a good suggestion, I will look into it and thanks.

                                Lord Yggdrasill wrote:

                                The idea is to find how to use string in OO way, $string->toUpperCase() instead of strtoupper($string). I am not saying the procedural way wont work, just trying to seek for a better alternative.

                                In themselves, both ways are OO and procedural, and pretty much equally good 😉

                                  Lord Yggdrasill wrote:

                                  I am not saying the procedural way wont work, just trying to seek for a better alternative.

                                  Well, you haven't exactly sold us on the benefits of using a String class instead of strings, beyond your answer to NogDog's comment:

                                  NogDog wrote:

                                  ....show me something I can do with that String object I can't already do with "normal" strings in PHP

                                  umm the only exclusive feature it has compared to procedural string usage is that the content inside a string is a private property.

                                  which leaves me asking "....So?"

                                    Lord Yggdrasill;11004043 wrote:

                                    ... In Javascript you can declare a string object in either one of the two ways:

                                    // Approach 1:
                                    text = "This is a string";
                                    
                                    // Approach 2:
                                    text = new String("This is a string");
                                    

                                    And these two make no difference.

                                    I know this isn't really the subject of the thread, but those javascript strings are different. One is a string literal (not an object), and the other is an object (of the String prototype).

                                    Many times, there is no practical difference - meaning, you won't notice. Javascript does automatic type conversions when dealing with string literals (which is why you can use methods on them), but they are still different at their most basic levels.

                                    To illustrate:

                                    a = "abc";
                                    b = "abc";
                                    c = new String("abc");
                                    d = new String("abc");
                                    e = "1+1";
                                    f = new String( "1+1" );
                                    
                                    document.write( a == b );  // True
                                    document.write( c == d );  // False (!)
                                    document.write( eval(e) );  // 2
                                    document.write( eval(f) );  // 1+1
                                      Weedpacket;11004059 wrote:

                                      Well, you haven't exactly sold us on the benefits of using a String class instead of strings, beyond your answer to NogDog's comment:

                                      which leaves me asking "....So?"

                                      Well isnt the OO syntax a benefit of using string class? $string->toUpperCase() is better than strtoupper($string) from a programmer point of view if they carry out the same task with similar number of lines and memory usage.

                                        Well from my personal point of view, I feel its better to use variable types the way they are defined by the language natively. Also, from a programmers point of view there's no reason to create extra function calls. If you don't think its more function calls think about this: Every one of those methods in the class, calls the native function used to work with strings, along with an if statement to make sure its passed something viable.