Jump to content

OOP organization


The Little Guy

Recommended Posts

Anyone have any suggestions on how to set up php classes?

I have three at the moment, but I don't know if they are set up well.

I am making a question and answer site, ask a question, and it will return an answer.

 

So the user types in a question, then I need it to choose the proper class to use according to the question. Right now, I have it so when they type their question it goes through a class called "Parser" which takes the query and decides what the person is talking about, after that it runs a class that is closest to that query.

 

For example if the person types:

"how many feet are in a mile?"

 

It decides that it is a math question, and creates a "Math" class. Next, in the "Math" class it parses it even more and looks at that and sees that there is feet and miles, so this question is about distance comparison. so it then creates a third class called "Distance" which then calculates all types of distances.

 

Finally the returned result is:

"5280 feet = 1 mile"

 

I am not really sure if this is a good approach, I would like to easily be able to modify the classes to do other things, such as instead of "Math" do "Language" or "Shopping" etc. I would also like to be able to easily access values from the class that created the current class, but I am not sure how to do that...

 

Does anyone have a good or better approach to this? I am kind of stumped, and fairly new to PHP's OOP

 

Thanks!!!

Link to comment
Share on other sites

I would like my Distance class to extend my Math class, but from the amount of OOP I know I don't see the point, maybe you can help me out...

 

Here is the whole Math class:

<?php 
class Math{
public $query = "";
public $result;
public $distance;
public $special = array();
public $valid = FALSE;
public function __construct($string = "", $dist){
	$this->query = $string;
	$this->distance = $dist;
	$this->result = $this->parse();
}
public function parse(){
	// Distance
	if(preg_match("~(".implode("|", $this->distance).")~", $this->query)){
		$distance = new Distance($this->query, $this->distance);
		if(!$distance->valid){
			$this->valid = FALSE;
			return FALSE;
		}
		$this->info = $distance->info;
		$this->special = $distance->special();
		$this->valid = TRUE;
		return $distance->final;
	}
	return FALSE;
}
}
?>

 

I think the main problem, is that I can't just call the distance class based on the query, I have to call the math class, then decide which type of math class I need to use (distance, weight, adding, subtraction, etc.).  I feel I am making this harder than it needs to be...

 

I'm kinda confused right now...

Link to comment
Share on other sites

If all the math class does is decide which of 4 classes to create, why not create a function in the parsing class to do that? That seems like something a parsing function would do.

 

But yeah, about the other classes (distance, and what not) When I was talking about inheriting functions, these would be a good example. Im assuming, since they all answer some sort of math based question, that they have some similar attributes and methods. you could have them all extend one class. That way, since they are all basically the same type, so you can pass them into functions that use type hinting easier. for example, assume the base class was called MathHandler, and we use that to derive our other more specific classes from it

public function foo(MathHandler $math){

 

then you could pass any of the different classes into that function, and take advantage of polymorphism (if you wanted to).

 

 

But this is just a suggestion, you could do it a few different ways. However, I think inheritance would make sense here

Link to comment
Share on other sites

I don't under stand, when I create the Math class I need to create a Distance class, but in the distance class I don't need the Math classes' methods or properties any more, but I would like to set some properties that are in the calling class (Class that created the Distance class) from the distance class. This way I could use that property later on...

Link to comment
Share on other sites

Yea from the sound of it mikesta707 has it right.  Your math class is just a intermediate class.  Seems to me like your parser should take care of that.  Like when you call the operator they decide where to connect you.  If all your math class does is choose a type of math, then you are wasting code.  Your parser class should then have levels and sub levels.

 

By the way whatever your making seems awesome!  You should somehow try to harness the internet instead of hard coding these functions though, you can't account for everything.

Link to comment
Share on other sites

Well you aren't really wasting code. I was just saying that what the Math class does is basically one method that can (and perhaps should) be handled by the parsing class. Since all the math class does is create another class based on some regex, You can just get rid of that class all together and use the parser class to create one of the distance/whatever classes.

 

 

Now for the inheritance topic, just look at your math question classes, like distance or whatever. Compare them all, and see if they all have certain attributes/methods that are the same (perhaps basic attributes, accessors, mutators, etc.) If they have a set of attributes and methods that are pretty much the same, you can put those things into a Base class, and derive all the other classes from it. There are many advantages to use inheritance here, and it will make your code easier (in my opinion) to update and add stuff. if you want to add certain functionality to all the math question classes, instead of adding it one at a time you can add it to the base class and viola.

 

 

Link to comment
Share on other sites

I am going to have more in that math class, such as:

- Distance

- Weight

- Time

- Speed

- Basic Math

- etc...

 

Here is a basic overview of how I was planning on making my class structure

- Parser
- Math
	- Distance
	- Weight
	- Time
	- Speed
	- BasicMath
- Language
	- Dictionary
	- Thesaurus
- Reviews
	- Product
	- Business

 

For some reason I am not able to get my head to see this properly :( sorry...

 

Parser.php

<?php
class Parser{
public $distances;
private $query;
public function __construct($query, $pageType = 'default'){
	include 'helper/arrays.php';
	$this->distances = $distances;
	$this->query = $query;
	$categoryResult = $this->bestCategory();
	$this->spellCheck();
	$this->parse($categoryResult);
}
public function bestCategory(){
	$q = mysql_real_escape_string($this->query);
	$sql = mysql_query("
				SELECT * FROM `phrases` p LEFT JOIN `categories` c ON (p.category = c.id) 
				WHERE
				'$q' REGEXP p.phrase")or die(mysql_error());
	return mysql_fetch_array($sql);
	mysql_free_result($sql);
}
public function spellCheck(){
	$str = preg_replace("~\.|\?|/!~", "", $_GET['q']);
	$words = explode(" ", $str);
	$pspell_link = pspell_new("en");
	$errors = 0;
	$errorStr = "";
	foreach($words as $word){
		if(!pspell_check($pspell_link, $word)){
			$suggestions = pspell_suggest($pspell_link, $word);
			$errorStr .= "<b>".$suggestions[0]."</b> ";
			$errors++;
		}else{
			$errorStr .= $word." ";
		}
	}
	if($errors > 0){
		echo '<span style="font-weight:bolder;font-size:18px;">Did you mean:</span> <a href="?q='.strip_tags($errorStr).'">'.$errorStr.'</a>';
	}
}
public function parse($row){
	if($row['category'] == 'Math'){
		$math = new Math($_GET['q'], $this->distances);
		if($math->valid){
			$total = $math->result;
			$info = $math->info;
			echo "<h1>".$total."</h1>";
			if(!is_null($info)){
				echo "<h2>Additional Information:</h2>".$info;
			}
		}
	}
	if($row['category'] == 'Language'){
		echo "<h1>Definitions for {$_GET['q']}</h1>";
	}
}
}
?>

 

Math.php

<?php 
class Math{
public $query = "";
public $result;
public $distance;
public $special = array();
public $valid = FALSE;
public function __construct($string = "", $dist){
	$this->query = $string;
	$this->distance = $dist;
	$this->result = $this->parse();
}
public function parse(){
	// Distance
	if(preg_match("~(".implode("|", $this->distance).")~", $this->query)){
		$distance = new Distance($this->query, $this->distance);
		if(!$distance->valid){
			$this->valid = FALSE;
			return FALSE;
		}
		$this->info = $distance->info;
		$this->special = $distance->special();
		$this->valid = TRUE;
		return $distance->final;
	}
	return FALSE;
}
}
?>

 

Distance.php

<?php
class Distance{
public $query = "";

// Define the constants
const inch = 1;
const foot = 12;
const yard = 36;
const pixel = 72;
const mile = 63360;
const kilometer = 39370.0787;
const lightyear = 3.72461748E+17;

// Define the public properties
public $final;
public $info = null;
public $distances;
public $valid = TRUE;

// Define the private properties
private $metric = array("kilometer");
private $special = array();

public function __construct($string = "", $dist){
	$this->query = preg_replace("~,~", "", $string);
	$this->distances = $dist;
	$this->final = $this->parse();
}
public function special(){
	return $this->special;
}
public function parse(){
	// Find and create an array of the distances found in the string
	preg_match_all("~".implode("|", $this->distances)."~", $this->query, $matches);
	$arrQ = explode(" ", $this->query);
	$in = array_search("in", $arrQ) + 1;
	// if the following character isn't a number set count to 1
	if(is_numeric($arrQ[$in])){
		$count = $arrQ[$in];
	}else{
		$count = 1;
	}
	$v = array(array(), array());
	if(!isset($matches[0][0]) || !isset($matches[0][1])){
		$this->valid = FALSE;
		return FALSE;
	}
// First value settings
	// Distance type (mile, foot, inch, etc) saved as number from array 0 is samllest distance 
	// Metric or standard Found in private metric array
	$v[0][0] = array_search($matches[0][0], $this->distances);
	$v[0][1] = (in_array($matches[0][0], $this->metric))?'metric':'standard';
// Second value settings
	$v[1][0] = array_search($matches[0][1], $this->distances);
	$v[1][1] = (in_array($matches[0][1], $this->metric))?'metric':'standard';
// Remove spaces
	$matches[0][0] = str_replace(" ", "", $matches[0][0]);
	$matches[0][1] = str_replace(" ", "", $matches[0][1]);
// Set special items
	$this->special[0] = $matches[0][0];
	$this->special[1] = $matches[0][1];


	// Change feet to foot for eval and variable reasons
	if($matches[0][0] == 'feet'){
		$matches[0][0] = 'foot';
	}
	if($matches[0][1] == 'feet'){
		$matches[0][1] = 'foot';
	}
	// If value 0 is smaller than value 1 that means they are caulating a small number to a larger number
	// that is why the distance array needs to be set up from smallest to largest
	if($v[0][0] < $v[1][0]){
		// This holds the calculations for two standard distances
		if($v[0][1] == 'standard' && $v[1][1] == 'standard'){
			$str = '$value = (self::'.$matches[0][1].' * $count) * self::'.$matches[0][0].';';
		}
		// Run the string as code
		eval($str);
		// since all values are defaulted to inch, some values need to be caluclated further
		if($matches[0][0] == "foot" && $matches[0][1] == "mile"){
			// convert the inches into feet to get feet in x miles
			$value = ($value / 12) / 12;
		}
		if($matches[0][0] == "yard" && $matches[0][1] == "mile"){
			// convert the inches into yards to get yards in x miles
			$value = ($value / 36) / 36;
		}
		if($matches[0][0] == "mile" && $matches[0][1] == "lightyear"){
			// convert the inches into yards to get yards in x miles
			$value = ($value / 63360) / 63360;
		}
	}else{
		$str = '$value = (self::'.$matches[0][1].' * $count) / self::'.$matches[0][0].';';
		eval($str);
	}




// save any additional information
	if($matches[0][0] == "inch" || $matches[0][1] == "inch"){
		$this->info .= '
		<dl>
			<dt>Inches</dt>
			<dd>The distance from your finger tip to your first joint is about an inch.</dd>
		</dl>';
	}
	if($matches[0][0] == "foot" || $matches[0][1] == "foot"){
		$this->info .= '
		<dl>
			<dt>Feet</dt>
			<dd>A foot is 12 inches, which is average size of male human wearing a shoe.</dd>
		</dl>';
	}
	if($matches[0][0] == "pixel" || $matches[0][1] == "pixel"){
		$this->info .= '
		<dl>
			<dt>Pixels</dt>
			<dd>The average computer displays 72 pixels per inch, so are caluclations were bassed on 72 pixels in an inch.</dd>
		</dl>';
	}
	if($matches[0][0] == "lightyear" || $matches[0][1] == "lightyear"){
		$this->info .= '
		<dl>
			<dt>Light year</dt>
			<dd>
				Light travels at about 669,600,000 miles per hour, are calculations were based on inches in a lightyear.
				<ul>
					<li>A lightyear is a measurement of how fast light travels in one year.</li>
					<li>It takes 8 minutes for light to reach earth from the sun.</li>
					<li>The sun is on average 93 million miles away from the earth.</li>
				</ul>
			</dd>
		</dl>';
	}
	$opt1 = "";
	$opt2 = "";
	if($value > 1 || $value < 1){
		switch($matches[0][0]){
			case "pixel":$opt1="pixels";break;
			case "inch":$opt1="inches";break;
			case "foot":$opt1="feet";break;
			case "lightyear":$opt1="light years";break;
			case "mile":$opt1="miles";break;
		}
	}else{
		switch($matches[0][0]){
			case "pixel":$opt1="pixel";break;
			case "inch":$opt1="inch";break;
			case "foot":$opt1="foot";break;
			case "lightyear":$opt1="light year";break;
			case "mile":$opt1="mile";break;
		}
	}

	if($count < 1 || $count > 1){
		switch($matches[0][1]){
			case "pixel":$opt2="pixeles";break;
			case "inch":$opt2="inches";break;
			case "foot":$opt2="feet";break;
			case "lightyear":$opt2="light years";break;
			case "mile":$opt2="miles";break;
		}
	}else{
		switch($matches[0][1]){
			case "pixel":$opt2="pixel";break;
			case "inch":$opt2="inch";break;
			case "foot":$opt2="foot";break;
			case "lightyear":$opt2="light year";break;
			case "mile":$opt2="mile";break;
		}
	}

	// return the final value
	return "$value $opt1 = $count $opt2";
}
}
?>

 

I think what I may do, is change the categories in the database from "Math" and "Language" to "Distance", "Weight", "Speed" etc. I think that way I then wouldn't have to deal with creating a math class, just extending it....

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.