Welcome to Dream.In.Code
Getting Help is Easy!

Join 132,488 Programmers for FREE! Get instant access to thousands of experts, tutorials, code snippets, and more! There are 1,087 people online right now. Registration is fast and FREE... Join Now!




Manipulating Strings, OO Style

 
Reply to this topicStart new topic

> Manipulating Strings, OO Style, Creating your own class for manipulating data.

joeyadms
Group Icon



post 12 Jun, 2008 - 05:18 AM
Post #1


Manipulating Strings, OO Style

Intro
Whenever using php to output data on the web, it is common place to have to format
it so that it is visually stimulating, or to add emphasis. Depending on your configuration,
this may require echoing large amounts of html each time you output data. You may be using a template
engine, or a framework that allows view scripts, where the file is primarily html, but you put in place-holders
or echo the data wherever needed, this arguably is the easiest to debug, fastest to change, and the best
configuration.

Sometimes, however, you may not have the ability to use templating engines, or a framework, and may have to rely on
your own functions for manipulating data for output. Having to echo html several times over and over again, to
change simple things like color, or creating elements is a pain, and not friendly. Say you have an error message style, or a header
style, and everytime you use this data, you have to again and again echo html elements. This can lead to several
mistakes in html, and or php code.

What you should always remember when thinking of your code, is DRY, or Don't Repeat Yourself. Whenever
you find you are coding the same thing multiple times, it is time to step aside, think, and refactor.

In Comes OOP. Using the power of OOP in PHP, PHP5 especially, we can create objects that will handle string manipulation.

Creating the Base Class
So now that we know what we want to do, manipulate strings for output, lets create a class that we will expand on
to handle these functions.

NOTE: Remember, longer names do not take longer to execute in php, so make sure you name your methods, objects, and properties
something that is self-explanatory on function and return.

Class StringHelper
CODE

class StringHelper {


}


Brainstorming
Now that we have our base class, lets figure out what exactly we want to be able to do with it. What common things
do we need to do to strings. Come up with a list of what you need to do to them, in whatever way you like, I prefer mind-mapping.


Lets see, I have come up with this list
Escape - Prevent XSS Attacks by escaping html chars
Caps - Make string capitalize
CamelCase - Make every word capitalized by first letter
Sentence - Add period to end, Capitalize first letter
Color - Change color of data
Div/Span/P - Make html elements with supplied attributes
Is Email? - Check to see if data is a valid email address

Now lets refine that list. Cast out functions that are not related to the overall scheme. Is Email does help manage
strings, however we are wanting to strictly manipulate data for output. So lets eliminate that one, and while we are at it
lets choose a more descriptive class name for our helper.

Instead of StringHelper lets use StringFormatter.
Now lets create empty functions from the list provided.
CODE

class StringFormatter {

public function escape($string){}
public function color($string){}
public function caps($string){}
public function camel($string) {}
public function sentence($string) {}
public function div($string) {}
public function span($string){}
public function p($string) {}

}


Simple enough, empty functions, all accept the string that you want to manipulate.

Wrapping!!!!!
No, Not presents. What we do now, is take our functions, and compare them to functions already integrated into the PHP language.
Then we will just make the function a wrapper for the php-integrated function by just funneling our string into it and returning the output.
Like so!
CODE

public function escape($string){
    return htmlspecialchars($string);
}
public function caps($string){
    return strtoupper($string);
}
public function camel($string){
    return ucwords($string);
}

Now, you don't want to reinvent the wheel, so make sure you check around on google, and the php manual at php.net, to make
sure there isn't already a function for what you want to do. There are a lot of hidden gems in php.

OK, so we have knocked out a good bit of our work, now we need to figure out what we want the finished output from each
function to look like, and what arguments to accept to create this.

I will step through one of the functions, as you will get the picture, and I don't want to repeat myself (DRY remember smile.gif ) when not needed.

We will take our div function.

Creating methods

Ok so we want our div output to look at its most basic form like this <div>string</div>
and at it's most complex form, like this <div class=class id=id style=styles>string</div>
So this should be obvious, our arguments should be function div($string,$class,$id,$style) since all arguments other than the string can be optional, we will make them null by default and then check
in the method to see if they are null, if they are, then do nothing, else if they are not, we will create that part of the element.

So now our method looks like
CODE

public function div($string,$id=null,$class=null,$style=null){

}


Well first, we need to open our tag, there is no way around that, it will be static in all formations of output.
Then we will need to close the opening tag, echo our string, and close the div element alltogether, and then
return the formatted string. Now we leave space where
our logic will go, and come back to that later.

Now it looks like this
CODE

public function div($string,$id=null,$class=null,$style=null){
        $d = "<div"; // Open div tag
        // @todo: Check if null $id/$class/$style, create output for each.
        $d.= ">$string</div>"; // Close opening tag, output string,close element
        return $d; // return formatted string
    }


Easy enough, not too much headache, now lets check to see if each of our attributes are null or not.
Since we are doing nothing if they are null, there is no reason for else statements. Also, we will go ahead
and create our id and class attributes if they are not null, since it is as trivial as adding onto the existing
'$d' string.
CODE

public function div($string,$id=null,$class=null,$style=null){
        $d = "<div"; // Open div tag
        if(!is_null($id)){
          $d .= " id='{$id}'"; // Add ID attrib if not null
        }
        if(!is_null($class){
          $d.= " class='{$class}'"; // Add Class attrib if not null
        }
        if(!is_null($style){
          //Create styles
        }
        $d.= ">$string</div>"; // Close opening tag, output string,close element
        return $d; // return formatted string
    }


Now they will be able to pass multiple style definitions to this function, and whenever your dealing with
multiple named elements in php, or any other programming language, what is the most powerful thing you can rely
on? ARRAYSSSS , So instead of checking if $style is null, lets check to see if it is an array, if it is , lets cycle
through and create a attribute for each definition.

This is made very easy by PHP's handy array iterator, foreach()

CODE

public function div($string,$id=null,$class=null,$style=null){
        $d = "<div"; // Open div tag
        if(!is_null($id)){
          $d .= " id='{$id}'"; // Add ID attrib if not null
        }
        if(!is_null($class){
          $d.= " class='{$class}'"; // Add Class attrib if not null
        }
        if(is_array($style)){
            $d.= " style='"; // If we have style definitions, lets start our attribute
            foreach($style as $var => $val){
                $d.= "$var: $val; "; // foreach style attribute lets create Key=value from array
            }
            $d.= "'"; // Close our style definitions
        }
        $d.= ">$string</div>"; // Close opening tag, output string,close element
        return $d; // return formatted string
    }


It is that simple. We will accept an associative array with style definitions formatted in Key=Value style.
So with this added to our StringFormatter class, lets see an example of use.

Using your new class
CODE

include('stringformatter.class.php'); // Include our class file

$sf = new StringFormatter(); // Create instance of our class

$string = "Hello World!"; // Our string to manipulate.
$dangerous_string = "<script>alert('xss');</script>"; // A dangerous string

echo $sf->escape($dangerous_string); // safely output dangerous strings without fear

echo $sf->caps($string); // CAPS LOCK IS CRUISE CONTROL FOR COOL

$styles = array("color" => "red",
                "font-weight" => "bold"); // Styles
echo $sf->div($string,'footer','red_class',$styles); // echo our footer in bold red letters


Conclusion
Pretty awesome huh! So you see using some simple logic, and not a lot of work, you can create an object
oriented interface for formatting strings and other data. This will make it much easier when outputting data
to the browser, and save you a lot of time in the future. Blah Blah Blah ROI blah blah blah. smile.gif
Don't stop here either, you can create OO interfaces for handling all types of data.

My Gift To You
I have created a StringFormatter class, that does a lot of what we have covered here, along with a special addition.
I created a method, filter() that accepts the string to be formatted and an array of filters to apply.
This allows you to say, change the color, and make capital the string etc.. without having to do more variable definitions
or function withing function arguments.

The class is below, but here is an example of how to use the new filter method.
CODE

include('stringformatter.class.php'); // Include our class file
$filters = array('camel' => NULL,
                 'strtolower' => NULL,
                 'span' => array('null','login',array('font-weight' => 'bold','color' => 'red'))
                );


Now let me explain how it expects the filters array to be formatted.

CODE

$filters = array('function name' => array('argument2','argument3'));

You see this is an associative array with each key representing a method inside
our stringFormatter class, OR as you see above it can be a normal php function
(in the example above this was 'strtolower').

The value of each key is an array containing arguments for the function.
NOTE: The script passes the string to the function as the first argument, the array starts with argument2.

Complex example:
If you look here we specify some arguments, and one of which is an array of styles for our span method.
CODE

$filters = array('camel' => NULL,
                 'strtolower' => NULL,
                 'span' => array('null','login',array('font-weight' => 'bold','color' => 'red'))
                );

As you can also see, you can pass null arguments to functions.

DO NOT FORGET THAT THE KEY=Function. If the function has no arguments, specify it as
$filters = array('function' => NULL);


Here is the class file.

stringformatter.class.php
CODE

<?php
/**
* class StringFormatter
* @author Joey Adams
* @uses Manipulate strings for output
*
* You can check to see if the string is valid email address
* by using StringFormatter::is_email($str);
*
*
* $sf = new StringFormatter();
* $string = "hello world";
* echo $sf->color($string,'red');
*
* if($sf->is_email('joey@joeyadams.net')...
*
*
*
* MULTIPLE FILTERS::::
* You can format a string using multiple filters using
* StringFormatter::filter($string,$filter_functions_;
*
* Where  $string is the string to manipulate, and $filter_functions
* is an array formatted like this.
*
* $filterFunctions = array('Function Name' => array('argument1','argument2'));
*
* Here is some examples
*
* MULTIPLE FILTER EXAMPLES:::::
*
* $filters = array('camel' => NULL,
*                  'span' => array('null','login',array('font-weight' => 'bold','color' => 'red'))
*                     );
*
* If there are no arguments, but the sring itself, provide NULL, as it uses the Key = Function.
*
* If you include is_email as a function, it will check to see if it is an email first, if it is not, it will return 0,
* if so, it will continue formatting.
*
*
* NOTE: Make sure you include direct string filters first. Look below for example
*
* $f = array('color' => array('red'), 'camel' => null);
* echo $sf->filter('hello world',$f);
* This would output
* <span Style='color:red'>hello World</span>
*
*
*/
class StringFormatter{
    
    private function _call_func($string,$func,$arg,$is_method){
            switch(count($arg)){
            case 0:
                isset($is_method) ? $string = $this->$func($string):$string = $func($string);
                break;
            case 1:
                isset($is_method) ? $string = $this->$func($string,$arg[0]):$string = $func($string,$arg[0]);
                break;
            case 2:
                isset($is_method) ? $string = $this->$func($string,$arg[0],$arg[1]):$string = $func($string,$arg[0],$arg[1]);
                break;
            case 3:
                isset($is_method) ? $string = $this->$func($string,$arg[0],$arg[1],$arg[2]):$string = $func($string,$arg[0],$arg[1],$arg[2]);
                break;
            case 4:
                isset($is_method) ? $string = $this->$func($string,$arg[0],$arg[1],$arg[2],$arg[3]):$string = $func($string,$arg[0],$arg[1],$arg[2],$arg[3]);
                break;
            case 5:
                isset($is_method) ? $string = $this->$func($string,$arg[0],$arg[1],$arg[2],$arg[3],$arg[4]):$string = $func($string,$arg[0],$arg[1],$arg[2],$arg[3],$arg[4]);
                break;
        }
        return $string;
    }
    
    public function filter($string,$functions){
        if(is_array($functions)){
            if(array_key_exists('is_email',$functions)){
                if(!$this->is_email($string)){
                    return 0;
                }
            }
            foreach($functions as $func => $args){
                if(method_exists($this,$func)){
                    $string = $this->_call_func($string,$func,$args,1);
                } else if(function_exists($func)){
                    $string = $this->_call_func($string,$func,$args);                    
                }
            }
            return $string;
        }else{
            return 0;
        }
    }
    
    public function color($string,$color){
        return "<span style='color:{$color}'>$string</span>";
    }
    
    public function escape($string){
        return htmlspecialchars($string);
    }
    
    public function caps($string){
        return strtoupper($string);
    }
    
    public function lower($string){
        return strtolower($string);
    }
    
    public function camel($string){
        return ucwords($string);
    }
    
    public function sentence($string){
        if(substr($string,-1) != '.'){
            $string = $string . ".";
        }
        return ucfirst($string);
    }
    
    public function p($string,$class=null){
        is_null($class) ? $p = "<p>":$p = "<p class='{$class}'>";
        $p.= $string . "</p>";
        return $p;
    }
    
    public function div($string,$id=null,$class=null,$style=null){
        $d = "<div";
        is_null($id) ? null:$d.= " id='{$id}'";
        is_null($class) ? null:$d.= " class='{$class}'";
        if(is_array($style)){
            $d.= " style='";
            foreach($style as $var => $val){
                $d.= "$var: $val; ";
            }
            $d.= "'";
        }
        $d.= ">$string</div>";
        return $d;
    }
    
    public function span($string,$class=null,$style=null){
        $s = "<span";
        is_null($class) ? null:$s.= " class='{$class}'";
        if(is_array($style)){
            $s.= " style='";
            foreach($style as $var => $val){
                $s.= "$var: $val; ";
            }
            $s.= "'";
        }
        $s.=">$string</span>";
        return $s;
    }
    
    public function is_email($string){
        preg_match('/^[^0-9][a-zA-Z0-9_]+([.][a-zA-Z0-9_]+)*[@][a-zA-Z0-9_]+([.][a-zA-Z0-9_]+)*[.][a-zA-Z]{2,4}$/',
        $string) ? $r = 1:$r = 0;
        return $r;
    }
}

Go to the top of the page
+Quote Post


Register to Make This Ad Go Away!


Reply to this topicStart new topic
1 User(s) are reading this topic (1 Guests and 0 Anonymous Users)
0 Members:

 

Lo-Fi Version Time is now: 11/22/08 04:23PM

Live Help!

Tutorials

Programming

Web Development

Reference Sheets

Code Snippets

Bye Bye Ads

Free DIC T-Shirt

T-Shirt Example

Related Sites

Monthly Drawing

Thumb Drive

Partners

Top Contributors

Top 10 Kudos This Month