SitePoint Sponsor |
|
User Tag List
Results 76 to 100 of 136
Thread: How much OO is too much?
-
Aug 4, 2005, 09:20 #76
- Join Date
- Nov 2001
- Location
- Bath, UK
- Posts
- 2,498
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by stereofrog
For the PHP4 people, you can get a file_put_contents from PHP_Compat.
DouglasHello World
-
Aug 4, 2005, 09:23 #77
- Join Date
- Oct 2001
- Posts
- 656
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
ability to vary persistance (i.e. choose to store in db instead of a file)
-
Aug 4, 2005, 09:31 #78
- Join Date
- Jun 2003
- Location
- Iowa, USA
- Posts
- 3,749
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by Captain Proton
Next on the list would be compatability with current infrastructure. This would be why you would want to support multiple varities of db for a project. Is seems weird, but it is easier for me to justify using an open source project here at work if I can run it on top of oracle instead of mysql.
-
Aug 4, 2005, 09:41 #79
- Join Date
- Nov 2004
- Location
- Romania
- Posts
- 848
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by Captain Proton
-
Aug 4, 2005, 10:07 #80
- Join Date
- Sep 2001
- Location
- Somewhere in this vast universe
- Posts
- 3,741
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Ok, we have an HTML form, thats not even PHP, thats just a plan html page:
Code:if(isset($_POST['submit'])) { $name=$_POST['name']; $comment=$_POST['comment']; $name=strip_tags($name); $comment=$strip_tags($comment); $insertg="INSERT in guestbook (name, comment) values('$name','$comment')"; mysql_query($insertg); print "Entry added."; }
Code:$getentries=mysql_query("SELECT * from guestbook order by ID DESC"); while($getentries2=mysql_fetch_array($getentries)) { print "Name:$getentries2[name]<br>Comment:$getentries2[comment]<br><hr>"; }
Code:if(!get_magic_quotes_gpc()) { $_GET = array_map('mysql_real_escape_string', $_GET); $_POST = array_map('mysql_real_escape_string', $_POST); $_COOKIE = array_map('mysql_real_escape_string', $_COOKIE); } else { $_GET = array_map('stripslashes', $_GET); $_POST = array_map('stripslashes', $_POST); $_COOKIE = array_map('stripslashes', $_COOKIE); $_GET = array_map('mysql_real_escape_string', $_GET); $_POST = array_map('mysql_real_escape_string', $_POST); $_COOKIE = array_map('mysql_real_escape_string', $_COOKIE); }
-
Aug 4, 2005, 10:12 #81
- Join Date
- Oct 2001
- Posts
- 656
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
$getentries=mysql_query("SELECT * from guestbook order by ID DESC");
while($getentries2=mysql_fetch_array($getentries))
{
print "Name:$getentries2[name]<br>Comment:$getentries2[comment]<br><hr>";
}
-
Aug 4, 2005, 10:17 #82
- Join Date
- Jan 2003
- Posts
- 5,748
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Yer, I had forgotten just how bad PHP could be, if used in the wrong hands
-
Aug 4, 2005, 10:37 #83
- Join Date
- Sep 2001
- Location
- Somewhere in this vast universe
- Posts
- 3,741
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Its just a small example. It works doesn't it?
I'm not writing a class just to echo or print 1 line.
Want to tell me whats so horribly wrong with that print code and how you would do it?
-
Aug 4, 2005, 11:26 #84
- Join Date
- Nov 2001
- Location
- Bath, UK
- Posts
- 2,498
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by stereofrog
PHP Code:class Guesbook {
function get_content() {
$content = @file_get_contents('guestbook.txt');
if(strlen($c = htmlspecialchars(trim(@$_POST['comment'])))) {
file_put_contents('guestbook.txt', "$content$c<hr />");
header("Location: http://{$_SERVER['SERVER_NAME']}{$_SERVER['SCRIPT_NAME']}");
}
return $content;
}
}
$guestbook = new Guesbook;
?>
<h1>Guesbook 0.0.3</h1>
<?php echo $guestbook->get_content() ?>
<form action="?" method="POST">
<textarea name="comment" rows="20" cols="20"></textarea><br />
<input type="submit" value="add comment to guestbook" />
</form>
Regards,
DouglasHello World
-
Aug 4, 2005, 11:29 #85
- Join Date
- Aug 2004
- Location
- California
- Posts
- 1,672
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by Dr Livingston
For larger scripts (Marcus notes the 100 line mark) scripts become much less maintainable, flexible and testable -- especially for teams.Christopher
-
Aug 4, 2005, 11:31 #86
- Join Date
- Nov 2004
- Location
- Romania
- Posts
- 848
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by Archbob
. But anyway, it is wrong because you always have to have some sort of error handling, even in "working code". So you never should call mysql_query and mysql_fetch_array directly.
-
Aug 4, 2005, 11:51 #87
- Join Date
- Oct 2001
- Posts
- 656
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Want to tell me whats so horribly wrong with that print code and how you would do it?
It may sound stupid, but variable names (like function names and class names) are important. Meaningful names say that you yourself understand what the code does and it also helps other people who read the code to understand it.
In nitpicking mode I could also say something about the use of constants for array indices ($getentries2[name] instead of $getentries2['name']).
So, nothing to do with the lack of a class or not being OO enough, you see
-
Aug 4, 2005, 11:52 #88
- Join Date
- Sep 2001
- Location
- Somewhere in this vast universe
- Posts
- 3,741
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
I always put or die(mysql_error()) in the query . But that was just a simple example, so I left it out.
I usually don't use the empty function to determine if a string is empty, I always do:
Code:if(strlen($name)<1) { print "String is empty."; }
Ok, $getentries and $getentires are easy for anyone to understand because basically anyone can understand whats contained in the array are the guestbook entries. I name variable names on what they will display, not what kind of data they are.
-
Aug 4, 2005, 12:45 #89
- Join Date
- Nov 2001
- Location
- Bath, UK
- Posts
- 2,498
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Might be clearer as:
PHP Code:if ($string == "") {
// string empty...
}
if ($string != "") {
// string not empty...
}
I always put or die(mysql_error()) in the query .
Regards,
DouglasLast edited by DougBTX; Aug 4, 2005 at 13:15.
Hello World
-
Aug 4, 2005, 13:13 #90
- Join Date
- Sep 2003
- Location
- Glasgow
- Posts
- 1,690
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by Archbob
-
Aug 4, 2005, 13:19 #91
- Join Date
- Sep 2003
- Location
- Glasgow
- Posts
- 1,690
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by Archbob
-
Aug 4, 2005, 13:52 #92
- Join Date
- Sep 2001
- Location
- Somewhere in this vast universe
- Posts
- 3,741
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
I said that was just a small example, usually I would check to see if there is something in those fields. mysql_error() is when I'm developing something to see where the error is. I do strip_tags, I use mysql_escape-string to get injections and all the good stuff. That was just a small mini-example, sheesh.
-
Aug 4, 2005, 14:20 #93
- Join Date
- May 2002
- Location
- Gent, Belgium
- Posts
- 284
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by DougBTX
Can you explain the difference? From my perspective, those two things are really the same, because user input changes the state of objects. If that new state is invalid, I can spit errors back at the user.
For example we could have input of a date of birth, we could validate that input to be a valid date (ie. February 36 would be an invalid date).
When validated, regardless of the context the date is going to be used in, it is considered a "valid" date. But, if we have that user's-age+18-rule, then that +18 rule would be a precondition of, let's say, a setAge($age) method. The "user must be older than 18" is a business rule, the "valid date" rule is not.
In fact, in this case it is even more a question of separating presentation (the date input field) from business logic (the user must be older than 18), depending on the design, "date of birth" might not even be a property of the User class.
In DbC, the +18 rule would be a precondition, something equivalent toPHP Code:class User {
// @pre: $age >= 18
// @post: getAge() == $age
function setAge($age) {
$this->_age = $age;
}
}
To sum up, I think validation outside objects is necessary to satisfy the preconditions of the contracts and when they cannot be satisfied to present an application user meaningfull messages without having to put objects in invalid states in between.
I think validation inside the object is necessary to be able to crash early if a contract is breached. Inside is about software quality, outside is mainly about user experience and security.
Does that mean you have a User and a UserValidator? Or do you just have a generic Validator which you initialize when you need it like in Chris's example?
Taking "the" example for polymophism:...
In a language like PHP we could adhere to a strict naming convention and dynamically instantiate objects based on prefixes.
Or, we could put a getCalculator() method in the ClosedFigure interface.
Or we could implement some hashtable lookup and work with a factory
...Per
Everything works on a PowerPoint slide
-
Aug 4, 2005, 16:20 #94
- Join Date
- Nov 2001
- Location
- Bath, UK
- Posts
- 2,498
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by been
I wonder, is there a difference between validating the length of a string and validating the magnitude of a number? You seem to be suggesting that the former should happen outside the object, but the latter should be done internally.
Originally Posted by been
It sounds like the former, where you have a validator for each form, hence one for each request. Like building a wall around your domain objects so that you know they will always be protected from your users.
I guess you hate the idea of me throwing $_REQUEST straight into an object, and just expecting it to work
Originally Posted by been
Originally Posted by been
It doesn't really matter whether I'm looking at a Signup page, or an EditUser page, or anything else. A valid user is a valid user. It means I have the equivalent of a validator per Thing-I-want-to-persist, rather than a validator per request. The Thing knows if it can be saved or if it can't be saved, lets ask it.
Originally Posted by been
I'm not denying the existance of alternatives to polymorphism, I'm just saying it is the best tool to use in this case. A strict naming convention and arrays will get you most of the way to reimplementing objects, I believe Drupal tries to pull off this trick. The getCalculator() method I covered, "so you might have $shape->area_calculator instead ... but then you only ever need to access it through $shape->area() so lets make $shape->area_calculator private ...", but you're not taking it as far as it will go. Unless you need a calculator which you can apply to something other than the original Shape object, but you'd need to show me where you need that to justify the extra code you need to handle that case. Hash tables, I assume using the class name as the key? You're back to function prefixes and passing $self variables around I'm afraid.
The analogy might look a bit skewed if you are more interested in validating requests rather than the data you are putting in your database, but as I'm trying to argue, you don't need to validate the requests themselves.
With dynamic typing, you don't need to worry when someone tries to set their age to "John", there will be no "Cannot assign String 'John' to integer field" exceptions, until you try and put in in your database. You'll pick the error up when you validate the object, and you find that "John" is in no way bigger than 18.
Regards,
DouglasHello World
-
Aug 4, 2005, 16:41 #95
Originally Posted by Archbob
-
Aug 4, 2005, 20:19 #96
- Join Date
- May 2002
- Location
- Gent, Belgium
- Posts
- 284
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by DougBTX
No, I don't see that much difference in checking a string's length and the magnitude of a number.
I do however feel that there's a difference between checking the magnitude of a number and a business rule (that might involve checking the magnitude of a number)
Which is more important to you, validation of the request or validation of the affects of the request?
It sounds like the former, where you have a validator for each form, hence one for each request. Like building a wall around your domain objects so that you know they will always be protected from your users.
The most important to me though is that the preconditions (and invariants) of a contract are met before I message the object, it's the only way I can be sure that the object will obey the contract and meet it's postconditions.
In DbC, meeting the preconditions is the responsibility of the client, so from that view it makes no sense having validation in the supplier. OTOH, since PHP hasn't got contracts build into the language, I feel we need enough validation in the supplier to at least error if a client does not obey the contract. The problem with this is code duplication (yuck) and that's one of the things that could probably be resolved by building a contract tool; the tool could generate the internal validation and the contracts could also be used for generating various validators.
I guess you hate the idea of me throwing $_REQUEST straight into an object, and just expecting it to work
But that never happens. If the application halted on setAge, I might never get to setBirthday, so I wouldn't be able to tell them that February 36 doesn't exist.
Another issue is the seperation between ui and domain; we might have a fancy date picker in the form to select a date of birth, but our domain class might only have 'age' as property, so we might have to validate a string in "Month DayOfMonth Year" format, while our domain object just works with an age. Of course, that rather useless User class with the setAge() method we're using as example doesn't help either
It doesn't really matter whether I'm looking at a Signup page, or an EditUser page, or anything else. A valid user is a valid user. It means I have the equivalent of a validator per Thing-I-want-to-persist, rather than a validator per request. The Thing knows if it can be saved or if it can't be saved, lets ask it.
Aren't those just backdoors to polymorphism like BerislavLopac was trying to write using require?
I'm not denying the existance of alternatives to polymorphism, I'm just saying it is the best tool to use in this case. A strict naming convention and arrays will get you most of the way to reimplementing objects, I believe Drupal tries to pull off this trick. The getCalculator() method I covered, "so you might have $shape->area_calculator instead ... but then you only ever need to access it through $shape->area() so lets make $shape->area_calculator private ...", but you're not taking it as far as it will go. Unless you need a calculator which you can apply to something other than the original Shape object, but you'd need to show me where you need that to justify the extra code you need to handle that case. Hash tables, I assume using the class name as the key? You're back to function prefixes and passing $self variables around I'm afraid.
I still feel the analogy's skewed though: 'area' is a property of a closed figure, but what is 'being valid'? And whereof is it a property? And although not as elegant, polymorphism is still possible if needed, it just doesn't seem to be that necessary to me in this case.
The analogy might look a bit skewed if you are more interested in validating requests rather than the data you are putting in your database, but as I'm trying to argue, you don't need to validate the requests themselves.
Granted, you don't need to validate the requests, you don't need to do anything, you can even just take $_REQUEST, massage it into an sql query, send it over a db connection and see what happens
Btw, suppose one does not use the Active Record pattern, but a DataMapper. In your view, where does the validation part (after filling out a form) go then? I'm genuine curious because, if I understand you correctly, the validation code would be triggered when $user->save() is called (using AR). When using a DataMapper, it'll probably be something like $mapper->save($user), so would you put the validation code into the mapper then?
Although we seem to indeed come in on this with totally different angles, the discussion makes me think about the stuff just that little bit more, for which I thank you sincerely.Per
Everything works on a PowerPoint slide
-
Aug 13, 2005, 16:28 #97
- Join Date
- Nov 2001
- Location
- Bath, UK
- Posts
- 2,498
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by been
PHP Code:$object = new Object($data);
if ( $object->save() )
{
# code...
}
PHP Code:$object = new Object($data);
if ( $mapper->save($object) )
{
# code...
}
PHP Code:class Mapper
{
function save( $object )
{
if ( $object->is_valid() )
{
// map and save the object
}
}
}
Here's how I see it, as a distinction between Models and Domain objects:
A Domain object represents something inside the domain, which must be mapped to a database.
A Model represents something external the we want to manipulate, which must handle its own persistance.
The rest is down to how you want to implement Design by Contract (not whether you have contracts or not). If you took a DomainObject and an ObjectMapper, then wrapped them in a Façade which could enforce pre-conditions when you invoke the Mapper, you would probably end up with something close to the Model that I'm thinking of.
With domain objects, you've got to put the contracts up front, because, almost by definition, you can't do any validation during mapping. Because I like the Shape more than the User too, and I still need to justify my example, I'll stick with it for now.
Here is our rule:
Originally Posted by Shape
PHP Code:class Shape
{
function __construct ( $color )
{
$this->assert('color', in_array($color, array("green", "orange", "purple")), "What is this colour?");
# passed the contract, so continue
$this->color = $color;
}
function assert ($field, $valid, $message = "Contract not fulfilled" )
{
if ( !$valid )
{
throw new ConditionException ($field, $message);
}
}
}
PHP Code:if (in_array($_REQUEST['color'], array("green", "orange", "purple"))
{
$shape = new Shape($_REQUEST['color']);
$mapper->save($shape);
}
else
{
# send the form back with error messages...
}
PHP Code:try {
$shape = new Shape($_REQUEST['color']);
$mapper->save($shape);
}
catch (Exception $e)
{
# send the form back with error messages...
}
PHP Code:try {
$shape = new Shape($_REQUEST['color']);
$shape->save();
}
catch (Exception $e)
{
# send the form back with error messages...
}
So this is why I like the Model setup more, because it lets you get around that, (barring revelations of something I've missed about the Domain object implementation)
An ActiveRecord model could look like this:
PHP Code:class Shape extends ActiveRecordBase
{
function __construct ( $color )
{
$this->color = $color;
}
function validate ( )
{
$this->assert('color', in_array($this->color, array("green", "orange", "purple")), "What is this colour?");
}
}
So, when is it most useful to call the validate method?
Because we are on the web, with corse grained requests (all the user data from the request comes in in one block of url encoded data, all our responce goes out in one block of XML encoded data), I think we should call validate as late as possible. It doesn't matter how $this->color gets set, as long as it is set by the time we want to do anything with it.
And what do we want to do with it? One thing is to save it to the database, which is a perfect oppertunity to call validate. save() belongs to ActiveRecordBase, which will call our validate code, letting us write:
PHP Code:$shape = new Shape($_REQUEST['color']);
if ( !$shape->save() )
{
# send the form back with error messages...
}
But we're not done yet. As we are are talking about ActiveRecords, we can ask the Record what it looks like. What do you look like? I've got a "color" field!
That means we don't need to write the $this->color = $color line anymore, we can just pass in an array, and the ActiveRecord can pull in the data it has fields for. One less thing to worry about. Here's what our reflective ActiveRecord class looks like:
PHP Code:class Shape extends ActiveRecordBase
{
function validate ( )
{
$this->assert('color', in_array($this->color, array("green", "orange", "purple")), "What is this colour?");
}
}
PHP Code:$shape = new Shape($_REQUEST);
if ( !$shape->save() )
{
# send the form back with error messages...
}
Regards,
DouglasHello World
-
Aug 13, 2005, 16:43 #98
- Join Date
- Sep 2003
- Location
- Glasgow
- Posts
- 1,690
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by DougBTX
-
Aug 13, 2005, 16:55 #99
- Join Date
- Nov 2001
- Location
- Bath, UK
- Posts
- 2,498
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Originally Posted by McGruff
Specifically: using a domain is one way to write a model layer. MVC is a more generic idea than domains.Hello World
-
Aug 13, 2005, 17:56 #100
- Join Date
- Sep 2003
- Location
- Glasgow
- Posts
- 1,690
- Mentioned
- 0 Post(s)
- Tagged
- 0 Thread(s)
Sorry to contradict you but that's definitely not correct. What are your references for this?
Bookmarks