Object base class

Coding Critique is the place to post source code for peer review by other members of DevNetwork. Any kind of code can be posted. Code posted does not have to be limited to PHP. All members are invited to contribute constructive criticism with the goal of improving the code. Posted code should include some background information about it and what areas you specifically would like help with.

Popular code excerpts may be moved to "Code Snippets" by the moderators.

Moderator: General Moderators

Post Reply
User avatar
yacahuma
Forum Regular
Posts: 870
Joined: Sun Jul 01, 2007 7:11 am

Object base class

Post by yacahuma »

Hello,

For a long time I have been using this class and it makes my job a lot easier. I would like to share it with you. Comments are welcome

Code: Select all

<?
class Object 
{

  var $updtFields;
 	function Object($record="")
  {
		  $this->arrayToObject($record);
				
	 } 
	 
	 function arrayToObject($record="")
	 {
       if (is_array($record))
			 {
			   $this->updtFields = array();
	   		foreach(array_keys(get_class_vars(get_class($this))) as $k)
				if (isset($record[$k]))
				{
					//echo "SETTING $k ->" . $record[$k] . "<BR>";
					$this->$k = $record[$k];
					$this->updtFields[] = $k;
				}
			 }	
	 }
	   
   function toDebug()
   {
   		foreach(array_keys(get_class_vars(get_class($this))) as $k)
			echo "$k = [" . $this->$k . "]<BR>\n";
		echo '<HR>';	

  }

   function toXML($octags,$vars=0)
   {
	    $bad = array("&","\r\n" );
      $good  = array("&","");
	    $xml='';
	    if ($octags)
			  $xml='<'. get_class($this) . '>';
   		foreach(array_keys(get_class_vars(get_class($this))) as $k)
			  if ($vars ==0  || in_array($k,$vars))
			     $xml .= "<$k>" . str_replace($bad,$good,html_entity_decode ($this->$k, ENT_QUOTES, 'ISO-8859-1')). "</$k>";
					 
	    if ($octags)
			  $xml .= '</'. get_class($this) . '>';
			return $xml;	

  }
  
   function toStr($ch="\n")
   {
	    $str='';
   		foreach(array_keys(get_class_vars(get_class($this))) as $k)
			{
			   if ($k != 'updtFields')
			      $str .= $k .'=' . urlencode($this->$k) . '&';
			}		
			return $str;		

  }
	
   function toUrl()
   {
	   return $this->ToStr('&');
  }

   function exportAllSet( $inglue = '>', $outglue = '}')
   {
       $return = '';
       foreach ($this->toArrayAllSet() as $tk => $tv)
           $return .= $outglue . $tk . $inglue . $tv;
       return substr($return,strlen($outglue));
   }
  
   function export( $inglue = '>', $outglue = '}')
   {
	    $str='';
   		foreach(array_keys(get_class_vars(get_class($this))) as $k)
			   if ($k != 'updtFields')
			      $str .= $outglue . $k . $inglue . $this->$k;
      return substr($str,strlen($outglue));

   }
  
  
   function import($str, $inglue = ">", $outglue = '}')
   {
       $hash = array();
       foreach (explode($outglue, $str) as $pair)
       {           
           $k2v = explode($inglue, $pair);           
           $hash[$k2v[0]] = $k2v[1];           
       }
       $this->arrayToObject($hash);			 
   }

  function toArray($toTrim)
  {
  		$arr = array();
   		foreach(array_keys(get_class_vars(get_class($this))) as $k)
		{
			if (!in_array ($k, $toTrim)) 
				$arr[$k] = $this->$k;
		}	
		return $arr;	
  }
  
  function toArrayAllSet()
  {
  		$arr = array();
   		foreach(array_keys(get_class_vars(get_class($this))) as $k)
		{
			if (in_array ($k, $this->updtFields)) 
				$arr[$k] = $this->$k;
		}	
		return $arr;	
  }
  function toArrayAllSetExcept($toTrim)
  {
  		$arr = array();
   		foreach(array_keys(get_class_vars(get_class($this))) as $k)
		{
			if (in_array ($k, $this->updtFields) && !in_array ($k, $toTrim)) 
				$arr[$k] = $this->$k;
		}	
		return $arr;	
  }

	
  function trim()
  {
   		foreach(array_keys(get_class_vars(get_class($this))) as $k)
			 if (!is_array($this->$k))
			   $this->$k = trim($this->$k);
  }
	
  function protectStr($string)
  {

		$string = str_replace(";", "", $string);
		return $string;

  }
	
	
	function protect()
	{
   		foreach(array_keys(get_class_vars(get_class($this))) as $k)
			$this->$k = Object::protectStr($this->$k);
	}
	function removeAllTags(){
   		foreach(array_keys(get_class_vars(get_class($this))) as $k)
			$this->$k = Object::html2txt($this->$k);
	}
	
	function html2txt($document)
	{
   $search = array('@<script[^>]*?>.*?</script>@si',  // Strip out javascript
               '@<[\/\!]*?[^<>]*?>@si',            // Strip out HTML tags
               '@<style[^>]*?>.*?</style>@siU',    // Strip style tags properly
               '@<![\s\S]*?--[ \t\n\r]*>@'         // Strip multi-line comments including CDATA
   );
   $text = preg_replace($search, '', $document);
   return $text;
  }
	
	 function json_encode()
   {
	   $encode =''; 
   		foreach(array_keys(get_class_vars(get_class($this))) as $k)
			   if ($k != 'updtFields')
			      $encode .= "\"$k\":\"{$this->$k}\",";
		  return '{' . substr($encode,0,strlen($encode)-1) . '}';	

  }//end of toDebug  
	
	
	function validateSchema($schema)
	{
		  $error = array();
			
		foreach(array_keys($schema) as $k)
		{	
				
		   // echo "VALIDATOIR STR[{$k}] = " . $schema[$k] . '<BR>';
		  	list($type,$len,$isnull) = split("," , $schema[$k] );

				$size = strlen($this->$k);
        if ($size == 0 && $isnull == 'Y')
				   return array(true,$error); //no errors
				else if ($size > $len)
				  $error[$k] = 'SIZE';
				else if ($isnull =='N' && $size==0)
				  $error[$k] = 'NULL';
				else if ($type == 'NUMBER')
				  if (!is_numeric($this->$k)) $error[$k] = 'NAN';
				else if ($type == 'VARCHAR2' || $type == 'CHAR')	
				  if (!is_string($this->$k)) $error[$k] = 'NAS';
		} 	//end ogf forech
		
		return array(count($error)==0,$error);

	}
	
	
	function loadData($data,$fields,$sep)
	{
	   $dataArr = split("[$sep]",$data);
		 if (count($dataArr) != count($fields))
		    return false;									
		 $i=0;
		 foreach ($dataArr as $val)
       $this->$fields[$i++] = $val;
		 return true;
	}

} //end of Object
?>

What can you do with it?

for example you can create a Customer Class

Code: Select all

<?
include 'lib/ObjectLib.php';

class Customer extends Object
{
  var $name;
  var $phone;
  var $ssn;
}
?>

If you have a form and you name all the form varibles exactly as the variables you could do fill your class like this

Code: Select all

//create a new Customer
$customer = new Customer($_POST);

//have problems? , just show all your data
$customer->toDebug();

//remove all spaces from user data
$customer->trim();

//Sometime you might want to send data from one page to another using a link, you can do this
<a href="senddata.php?<?=$customer->toUrl()?>">Send Data</a>

//Let say you want to export your data
$export = $customer->export();

//export your object to XML
echo htmlentities($a->toXML(true));

//export to XML only selected fields
echo htmlentities($a->toXML(true,array('name','phone')));

//validate your data 
just add this to your class
function isValid()
{

  $schema = array(
  ,'name'=>'VARCHAR2,20,N'
  ,'phone'=>'VARCHAR2,20,N'
  ,'ssn'=>'NUMBER,22,N'
);

       return $this->validateSchema($schema);
		
}//is valid

then you can 
list($isValid,$error) = $customer->isValid();

IMPORTANT NOTE: I have not dont this but it will be very easy to just add regular expressions to the validateSchema() so that your schema could look like
,'name'=>'REGEXP',<REGEX HERE>'



//NEED TO LOAD DATA FROM A TEXT FILE??
$d = new Customer();
$data='Jose;787-555-8888;988-98-99888';//this could be in a file
 $fields = array('name','phone','ssn');

//$d->PROCESS_CODE = "ADFF";
if ($d->load($data,$fields,';'))
{
   $d->toDebug();
   list($isValid,$error) = $d->isValid();
	 if (!$isValid)
	 {
	   die ("INVALID DATA ON");
	 }
	   
}
else
{
  echo "INVALID DATA SOURCE";
}


Well that's about it. This class is extremely easy to use. Let me know if you like it.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

Well it certainly has some very nice functionality. However I am not sure that it is appropriate to put all those features into one class. Nor am I sure I like the idea of base object classes in PHP in general. I would prefer to see this broken up into a number of classes that deal with specific functionality. The you could extent to get just the specific functionality that you need. I would guess that you rarely use more than 10%-20% of the functionality of your base class in any class that inherits it.

Broken up these classes might be of real interest to a number of people here.
(#10850)
User avatar
yacahuma
Forum Regular
Posts: 870
Joined: Sun Jul 01, 2007 7:11 am

you will be surprised

Post by yacahuma »

You will be surprise of how many I use in just one program. Maybe is the nature of what I do. You have a good point,
but every function has very little code. In terms of OO I think all this functions relate to the data in the object. They are all data transformation functions. That's why I put them all in just one place. Also since I use so many methods of the base class, it was easier to just have it in one place.

I understand all the concept of OO , but I over the years I developed my own sense of what OO means. I guess the simplest way to put it is that if I can do something with one line instead of a bunch of lines needed to create new objects that will talk to other objects, I will go with the on line method, even if is not purely OO.
I guess the perfect example will be this. It was from a question I had on bthe swift forum

Code: Select all

swift code...
$log =& Swift_LogContainer::getLog();
$log->setLogLevel(Swift_Log::LOG_EVERYTHING);
$swift =& new Swift( ... );
echo "<pre>" . htmlentities($swift->log->dump(true)) . "</pre>";

phpmailer code...
$mail->SMTPDebug = true;

I am not saying one is better than the other. I just prefer oneliners.


I also have a code generator that creates update, list, and edit pages. The code generator is in the form of a html page. You enter the username, password, table name and PK. It uses adodb for the database stuff.
User avatar
superdezign
DevNet Master
Posts: 4135
Joined: Sat Jan 20, 2007 11:06 pm

Re: you will be surprised

Post by superdezign »

yacahuma wrote:You will be surprise of how many I use in just one program.
It's not a matter of how many are used in a program, but how many are used in the particular object that is extended from it.
yacahuma wrote:In terms of OO I think all this functions relate to the data in the object. They are all data transformation functions. That's why I put them all in just one place. Also since I use so many methods of the base class, it was easier to just have it in one place.
That would imply library of functions would be used, not a base class. Maybe a class dedicated to data transformation that had a lot of static functions would be more appropriate.
yacahuma wrote:[..]even if is not purely OO. I guess the perfect example will be this. It was from a question I had on bthe swift forum

Code: Select all

swift code...
$log =& Swift_LogContainer::getLog();
$log->setLogLevel(Swift_Log::LOG_EVERYTHING);
$swift =& new Swift( ... );
echo "<pre>" . htmlentities($swift->log->dump(true)) . "</pre>";

phpmailer code...
$mail->SMTPDebug = true;

I am not saying one is better than the other. I just prefer oneliners.
That's not an example of what you said at all. This is just making it so that outside of the class, less commands are needed. Inside the class, the same amount of stuff is being done. The example let's you turn the debugging on or off, and the class handles the rest. Swift's example makes you specify how much logging you want to be done, and let's you handle the display. When a developer makes other other developers lack control, they are bound to receive complaints :P


Basically, there are certain things that a base object could be good for. Maybe for saving data between objects, or logging errors. But for what you are accomplishing, an outside class would be better.
User avatar
RobertGonzalez
Site Administrator
Posts: 14293
Joined: Tue Sep 09, 2003 6:04 pm
Location: Fremont, CA, USA

Post by RobertGonzalez »

I agree with arborint. A single superclass that involves functionality on several levels seems a bit contrary to good OO design.

I could see a simple base class with several extending classes that are called when needed rather than forcing that functionality into the code without the need for it.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

I do think there is some nicel functionality in there though. If it were broken up into base classes for debug, data access, XML, JSON, etc. they might be pretty useful classes and of interest to some people around here.
(#10850)
Post Reply