Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
KuruMonkey
Jul 23, 2004

revmoo posted:

Which brings me to another good question; what is the difference between just using classes/functions and fully object-oriented code? Is there a difference? What is the difference between an instantiated object and a class method you call to do work?

When you define a class, you are really defining a "type of thing", which can have a structure of data that defines it (attributes), and an interface through which you interact with that thing (methods). Classic example is a User class:

php:
<?
class User {
  protected $fname = '';
  protected $lname = '';

  public function __construct($fname, $lname) {
    $this->fname = strtolower($fname);
    $this->lname = strtolower($lname);
  }

  public function render() {
    return ucfirst($this->fname) . " " . ucfirst($this->lname);
  }
}
?>
When you instantiate an object of a certain class, you are creating a solid item of that type you defined. You supply at the time of instantiation, the set of data that defines that particular item. You then use the object through its interface.

php:
<?
$fred = new User('fred', 'flintstone');
// time passes ...
echo $fred->render();
?>
When you define a static (or class) attribute or function, you are defining an attribute that's shared between all instances of that class, but accessed without any particular instance. Similarly with a static function, you're defining a function that is (supposedly, hopefully) related to the class as a whole, but doesn't require a particular instance to relate to. Its tricky to give simple but meaningful examples of this. The usual one is a class that tracks the number of instances of it that you create:

php:
<?
    class Counter {
        
        protected static $instances = 0;
        
        public function __construct() {
            self::$instances++;
        }
        
        public function __destruct() {
            self::$instances--;
        }
        
        public function instances() {
            return self::$instances;
        }
        
    }
?>
NOTE: very commonly in PHP code (including mine) you'll find a class with only static methods used, basically, as a band-aid for the fact that PHP previous to 5.3.0 had no namespaces. So to be safe whan adding new functions to existing codebases, you wanted to limit the number of potential name clashes. Using only a single class name in the global namespace and scoping all your actual functions inside it was a workaround. 5.3.0 is still not common enough that you can sensibly rely on namespacing for code you expect to distribute, and especially if you expect other people to deploy it on arbitrary servers successfully. (also PHP's namespacing syntax is more than a bit pony, but that's a digression)

The point of that note is; that use of a class and static methods has NOTHING to do with OO.

quote:

Anyone have a good guide they can recommend for learning oop php? Most of the stuff I've found has been really thick on the metaphors and it makes it really hard to process. I don't care that a CAR is a VEHICLE, I want real-world explanations.

You could honestly do worse than the OOP page in wikipedia (http://en.wikipedia.org/wiki/Object-oriented_programming).
It gives a reasonable overview, and gives definitions for the terms you'll encounter. Use it as a menu of google terms.
Ask about those terms here, too.

quote:

This is a really noobish post I know. I've mostly just done web development based on other people's frameworks and CMS's and I'm trying to get a solid grasp on real web development, I want to progress to a full-on OOP php dev.

This always sounds a bit snarky, but; be aware that OOP in theory, and the OOP tools available in any given language, are different things. I'd suggest doing reading on OOP in general first, then applying those concepts to PHP. This may make things more frustrating (PHP doesn't exactly have best-in-breed OOP implementations) but it will make the OO learning you do hugely more useful.

OOP in general will introduce you to things that will improve you massively as a programmer in general; implementing those concepts in PHP is just an extra hurdle you have to deal with.


Some short snippets:

Classes are "types"

Objects are particular items of a "type"

Base Classes are generic types

Inheritance is the process of specialising a type (with a sub-class). Sub-classes can be used interchangably with superclasses, as long as the public interface of the super class is all thats used. (this is extremely useful in practice!)

Aggregation is the process of building complex classes/objects from a set of simpler ones.

Interfaces allow you to define a set of features something must have, and treat anything that meets those requirements as if it were the same "type" - it allows unrelated classes to be used interchangeably. (i.e. as for inheritance above, but for unrelated classes - also extremely useful)

Adbot
ADBOT LOVES YOU

excidium
Oct 24, 2004

Tambahawk Soars
I just started with CodeIgniter to re-write a project I made at work. Wanted to make it cleaner, more efficient and safer than it's currently configured.

My basic question is on how to access date when it passes from M->C->V.

I have my Model as follows:
php:
<?php

class Other_info_model extends CI_Model {

    function __construct()
    {
        parent::__construct();
    }
    
    function get_newest_bases()
    {
        $this->db->order_by('ID''desc');
        $query $this->db->get('bases'1);
        
        return $query->result();
    }
}

My Controller
php:
<?php

class Site extends CI_Controller {

    function index()
    {
        $this->load->library('table');
        $this->load->model('Other_info_model');
        
        $data['bases'] = $this->Other_info_model->get_newest_bases();
        
        $data['main_content'] = 'site_view';
        
        $this->load->view('includes/template'$data);
    }
}

And my view
code:
<div id="container">
	<?php echo $this->table->generate($bases); ?>
</div>
The result is
code:
Fatal error: Cannot use object of type stdClass as array in C:\wamp\www\TSS\system\libraries\Table.php on line 178
What the hell am I not understanding to be able to output this information using the HTML Table class? I can build my table manually, and output using $bases[0]->Value, but that seems to be a waste when I have this helpful class to use. If I try using <?php echo $this->table->generate($bases[0]); ?> in my view I get an "Undefined table data" error. I'm lost as to what I'm doing wrong.

486
Jun 15, 2003

Delicious soda

excidium posted:

code:
Fatal error: Cannot use object of type stdClass as array in C:\wamp\www\TSS\system\libraries\Table.php...
What the hell am I not understanding to be able to output this information using the HTML Table class?

I'm not very familiar with CodeIgniter, but it looks like your database query result is an object and the table thing you're trying to use expects to be given an array. A quick google search turned up this documentation which states that result() returns an array of objects: http://codeigniter.com/user_guide/database/results.html

maybe try return $query->result_array() instead in your model

edit: however, the table docs says it can accept a database result object, so I should maybe leave this to someone who knows what's going on!

486 fucked around with this message at 18:10 on Mar 16, 2011

excidium
Oct 24, 2004

Tambahawk Soars
Yea that's what I read and expected it just to work, but I changed it to the result_array() and it seems to be much better now. I appreciate the help, and if anyone wants to chime in on why the object doesn't work, I'd still be interested in knowing.

Thanks 486.

SETEC Astronomy
Jul 30, 2008

Too many secrets.

DaTroof posted:

Based on your description of what you're doing, I suspect that you would be better served by session variables. Maybe I'm wrong, but if you're willing to go into more detail about what you're trying to do, someone might be able to recommend a better (and MORE SECURE) solution.
I'm trying to write a simple URL shortener. Yes, I know about YOURLS, but I'm trying to learn PHP by writing little apps that are useful to me.

You know, the more I think about how to do this, the more I think I'm reinventing the wheel in the age of the automobile. Let me grossly simplify here: what if I just wanted a URL that was more like foo.com/var1, where"var1" is the short URL's ID string?

bobthecheese
Jun 7, 2006
Although I've never met Martha Stewart, I'll probably never birth her child.

SETEC Astronomy posted:

I'm trying to write a simple URL shortener. Yes, I know about YOURLS, but I'm trying to learn PHP by writing little apps that are useful to me.

You know, the more I think about how to do this, the more I think I'm reinventing the wheel in the age of the automobile. Let me grossly simplify here: what if I just wanted a URL that was more like foo.com/var1, where"var1" is the short URL's ID string?

mod_rewrite

code:
RewiteEngine On

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule /{.*} /redirect.php?id=$1 [L]
This will take anything which isn't an existing file or directory on your server, and pass it to "redirect.php", as $_GET['id']

Either add this to your apache configuration, or into a .htaccess file.

#EDIT: I should add, that if you then use a 'header("location: $url"); in that PHP script, then the intermediate step of 'redirect.php' will be invisible to the user.

bobthecheese fucked around with this message at 06:47 on Mar 17, 2011

Lumpy
Apr 26, 2002

La! La! La! Laaaa!



College Slice

excidium posted:

Yea that's what I read and expected it just to work, but I changed it to the result_array() and it seems to be much better now. I appreciate the help, and if anyone wants to chime in on why the object doesn't work, I'd still be interested in knowing.

Thanks 486.

You will note in the docs that they do not pass the *result* of the query, but the query object itself:

code:
$this->load->library('table');

$query = $this->db->query("SELECT * FROM my_table");
// note lack of $result = $query->result() here
echo $this->table->generate($query);
I haven't ever used CI2, but that jumped out at me in the docs when I followed 486's link.

excidium
Oct 24, 2004

Tambahawk Soars

Lumpy posted:

You will note in the docs that they do not pass the *result* of the query, but the query object itself:

code:
$this->load->library('table');

$query = $this->db->query("SELECT * FROM my_table");
// note lack of $result = $query->result() here
echo $this->table->generate($query);
I haven't ever used CI2, but that jumped out at me in the docs when I followed 486's link.

Yea I noticed that, but they're also doing that query directly from the Controller. How would you get the data from the Model to the Controller to the View without returning the results?

Golbez
Oct 9, 2002

1 2 3!
If you want to take a shot at me get in line, line
1 2 3!
Baby, I've had all my shots and I'm fine
So I'm toying with objects, figuring out how to structure it. I have a dumb object, Employee, which contains only the data itself. I then have EmployeeManager, which handles getting, writing, validating, etc. If I understood some earlier posts in this thread, this was a pretty good way to go.

However, Employees have Plans, and in this schema, Plans are objects as well. I have in the constructor for Employee, "$this->Plan = new Plan()", so that's fine, but in the Manager, when I get an Employee, I got to "$Employee->Plan = "... and then I froze. I might create a PlanManager class, so then, my options appear to be, in the EmployeeManager class, create a new PlanManager and then run "$Employee->Plan = PlanManager->Get($PlanID);, but it seemed weird to have to create PlanManager every time, though now as I write this maybe not. My other idea was to run it as a static method, a la "$Employee->Plan = PlanManager::Get($PlanID);", but it seems weird to call a static function from the equivalent regular function.

Or, am I just completely bungling this from the start?

Golbez fucked around with this message at 19:50 on Mar 17, 2011

bobthecheese
Jun 7, 2006
Although I've never met Martha Stewart, I'll probably never birth her child.

Golbez posted:

So I'm toying with objects, figuring out how to structure it. I have a dumb object, Employee, which contains only the data itself. I then have EmployeeManager, which handles getting, writing, validating, etc. If I understood some earlier posts in this thread, this was a pretty good way to go.

However, Employees have Plans, and in this schema, Plans are objects as well. I have in the constructor for Employee, "$this->Plan = new Plan()", so that's fine, but in the Manager, when I get an Employee, I got to "$Employee->Plan = "... and then I froze. I might create a PlanManager class, so then, my options appear to be, in the EmployeeManager class, create a new PlanManager and then run "$Employee->Plan = PlanManager->Get($PlanID);, but it seemed weird to have to create PlanManager every time, though now as I write this maybe not. My other idea was to run it as a static method, a la "$Employee->Plan = PlanManager::Get($PlanID);", but it seems weird to call a static function from the equivalent regular function.

Or, am I just completely bungling this from the start?

Objects own data, and a Plan, while being an object, is data. So your Employee object should either have a "plan" object, or keep the plan ID, and provide a Plan() method, which builds and returns the plan.

When you say you have an "EmployeeController" do you mean a class which provides simple methods for finding and searching for Employee objects, or something which sources the Employee data and puts that inside an employee object?

Other people may disagree, but I feel that the object itself should be able to build itself out, and any Controller type objects should only exist to handle finding the objects themselves.

So something like this:
php:
<?
class Employee {
    private $id;
    private $name;
    private $planid;
    
    __construct($id) {
        $this->id = $id;
        // SQL to find the name and plan ID for the employee
    }
    
    function Plan() {
        return new Plan($this->planid);
    }
}

class EmployeeController {
    static function search_by_name ($name) {
        // SQL to pull out employee IDs by name
        
        $employees = array();
        foreach ($ids as $id) {
            $employees[] = new Employee($id);
        }
        return $employees;
    }
    
    static function search_by_plan ($planid) {
        // SQL to pull out employee IDs by plan id
        
        $employees = array();
        foreach ($ids as $id) {
            $employees[] = new Employee($id);
        }
        return $employees;
    }
}
?>

Golbez
Oct 9, 2002

1 2 3!
If you want to take a shot at me get in line, line
1 2 3!
Baby, I've had all my shots and I'm fine

bobthecheese posted:

Objects own data, and a Plan, while being an object, is data. So your Employee object should either have a "plan" object, or keep the plan ID, and provide a Plan() method, which builds and returns the plan.
My idea was to have the Plan object be a property of the Employee object, and when I get an employee from the database, along with the plan_id, I then fill in the details for said Plan.

quote:

When you say you have an "EmployeeController" do you mean a class which provides simple methods for finding and searching for Employee objects, or something which sources the Employee data and puts that inside an employee object?
At present my idea is to have "Employee" just hold the data, and "EmployeeManager" or Controller or what not handle data access (dealing with MySQL), searching, validating, basically all of the access and logic.

quote:

Other people may disagree, but I feel that the object itself should be able to build itself out, and any Controller type objects should only exist to handle finding the objects themselves.
The advice I've gotten from here in the past was to go more towards value objects and data access objects, with the data in a 'dumb' object that doesn't interact at all with the database, and a repository/manager/whatyouwill object that assembles and transports said data.

quote:

So something like this:
php:
<?
class Employee {
    private $id;
    private $name;
    private $planid;
    
    __construct($id) {
        $this->id = $id;
        // SQL to find the name and plan ID for the employee
    }
    
    function Plan() {
        return new Plan($this->planid);
    }
}
?>
Incidentally, I'm not allowing an argument for construct, because I need to create blank objects (for new ones, etc). Maybe I should just do ($id = null).

quote:

php:
<?
class EmployeeController {
    static function search_by_name ($name) {
        // SQL to pull out employee IDs by name
        
        $employees = array();
        foreach ($ids as $id) {
            $employees[] = new Employee($id);
        }
        return $employees;
    }
    
    static function search_by_plan ($planid) {
        // SQL to pull out employee IDs by plan id
        
        $employees = array();
        foreach ($ids as $id) {
            $employees[] = new Employee($id);
        }
        return $employees;
    }
}
?>
This brings up two questions:

1) I was planning on EmployeeManager to be an actual instantiated object, rather than static. This, again, based on advice received a dozen or so pages back. But is this a good idea?

2) I've also considered something similar to your line $employees[] = new Employee($id);, but I don't trust it; with a table containing 170,000 entries, I've checked and PHP runs out of memory if you give it a broad enough search; apparently, it's folly to maintain an array of 120,000 arrays. :shobon: So I instead have the search return an array of IDs, and the IDs are loaded one-by-one by the view or function or what not. The exception to this is in areas - like Employees - where I know there aren't so many rows to make it run out of memory, but I'd like to be internally consistent on this front.

Golbez
Oct 9, 2002

1 2 3!
If you want to take a shot at me get in line, line
1 2 3!
Baby, I've had all my shots and I'm fine
Basically, to ask a question I've probably asked before: If I'm using dumb data objects (no DB access of their own), should the manager object be instantiated or called statically? I'm not sure I see a reason to instanticate it... what's wrong with $oEmployee = EmployeeManager::get($id)?

bobthecheese
Jun 7, 2006
Although I've never met Martha Stewart, I'll probably never birth her child.
It's largely personal preference, really. I don't see the point of a data object which isn't actually linked to the data. An object (in my opinion) should encapsulate both data and functionality. A controller you could build two ways, one as a simple, static search tool (like I did in the example), or as a full object itself which behaves like a linked list or a datasource, and implements such functions as next(), previous(), reset(), etc.

Either one is fine, and in your instance, the second would probably be preferable.

An object that encapsulates something in the database, though, should define the methods for getting and updating that information, even if it doesn't handle creation directly.

On the 'build the plan on request' thing, my preference is to leave building out objects like that until you need them, just in case someone else updates them. But then you're getting into a whole other ball game if you're looking at situations where multiple people could be modifying your data set.

#EDIT:

Golbez posted:

Basically, to ask a question I've probably asked before: If I'm using dumb data objects (no DB access of their own), should the manager object be instantiated or called statically? I'm not sure I see a reason to instanticate it... what's wrong with $oEmployee = EmployeeManager::get($id)?

The main thing I see wrong with that statement is that it implies you are getting an EmployeeManager object by ID (not an Employee object).

Also, if you have a dumb object, can you tell me any compelling reason why an associative array wouldn't do the same job?

bobthecheese fucked around with this message at 22:36 on Mar 17, 2011

Golbez
Oct 9, 2002

1 2 3!
If you want to take a shot at me get in line, line
1 2 3!
Baby, I've had all my shots and I'm fine
So what you're suggesting is...

* An Employee class, which is self-sufficient - I call "$o = new Employee", and I can do "$o->get($id)", "$o->write()", "$o->validate()", etc.
* An EmployeeManager class, which is where anything that involves more than one Employee is contained. Searching, iteration, etc.

This method means that I can simply call "$oEmployee->Plan = new Plan($PlanID);" when getting an employee.

It seems to make sense to me, but I'm [obviously] a novice OO programmer who has been getting lots of different advice from here. :)

Munkeymon
Aug 14, 2003

Motherfucker's got an
armor-piercing crowbar! Rigoddamndicu𝜆ous.



Golbez, why in the world are you even trying to load all 170,000 of them at once in one PHP session? It sounds like there's an interface/structural problem elsewhere if that's happening in a single query.

bobthecheese
Jun 7, 2006
Although I've never met Martha Stewart, I'll probably never birth her child.

Golbez posted:

So what you're suggesting is...

* An Employee class, which is self-sufficient - I call "$o = new Employee", and I can do "$o->get($id)", "$o->write()", "$o->validate()", etc.
* An EmployeeManager class, which is where anything that involves more than one Employee is contained. Searching, iteration, etc.

This method means that I can simply call "$oEmployee->Plan = new Plan($PlanID);" when getting an employee.

It seems to make sense to me, but I'm [obviously] a novice OO programmer who has been getting lots of different advice from here. :)

Pretty much, only I would use setters/getters, $plan = $oEmployee->get_plan(); or $oEmployee->set_plan(new Plan($PlanID)); (or even more simply, if there's no validation required while setting a plan $oEmployee->set_plan($PlanID);)

Try to avoid setting properties directly on an object, because if you need to add in validation later (i.e. you realise that you have to check that a plan ID actually exists, or people are trying to set emplyee IDs to negatives), it's much easier to throw validation into a single setter method than it is to grep your entire code base to figure out where/how to validate.

bobthecheese fucked around with this message at 22:42 on Mar 17, 2011

Golbez
Oct 9, 2002

1 2 3!
If you want to take a shot at me get in line, line
1 2 3!
Baby, I've had all my shots and I'm fine

Munkeymon posted:

Golbez, why in the world are you even trying to load all 170,000 of them at once in one PHP session? It sounds like there's an interface/structural problem elsewhere if that's happening in a single query.

Because the search returns all 170,000 records. :) Which is why I decided to have the search engine only return IDs; that way, I can get the whole list and then truncate before displaying. It was that, or the command to tell me the total number of results and still LIMIT, which still took the time to get the total number of results and required me running a second MySQL command. It seemed easier to just return the IDs and then snip the array as needed. (Note that this is for a page currently without pagination; it simply says, "too many results, refine your search")

Golbez
Oct 9, 2002

1 2 3!
If you want to take a shot at me get in line, line
1 2 3!
Baby, I've had all my shots and I'm fine

bobthecheese posted:

Pretty much, only I would use setters/getters, $plan = $oEmployee->get_plan(); or $oEmployee->set_plan(new Plan($PlanID)); (or even more simply, if there's no validation required while setting a plan $oEmployee->set_plan($PlanID);)

I figured all validation would occur at the last moment before entry into the database. Someone wants to put in a bum value for PlanID, they'll get an empty plan object, and the validation will complain when they try to do anything with it (which will probably be microseconds later).

And at the moment I'm going to skip getters/setters, in part because of that philosophy.

bobthecheese
Jun 7, 2006
Although I've never met Martha Stewart, I'll probably never birth her child.

Golbez posted:

I figured all validation would occur at the last moment before entry into the database. Someone wants to put in a bum value for PlanID, they'll get an empty plan object, and the validation will complain when they try to do anything with it (which will probably be microseconds later).

And at the moment I'm going to skip getters/setters, in part because of that philosophy.

Nah, bad idea. it just makes your code difficult to maintain. If you're trying to track down where a bum value came from, you want the exception thrown when it's set, not 200 lines later, when it's trying to save.

Especially if you're dealing with large number of objects, too. Waiting 20 seconds for all the objects to get updated incorrectly, then having it fall over when it tries to save the first one, or have it fall over when it tries to update the first object incorrectly?

bobthecheese fucked around with this message at 22:47 on Mar 17, 2011

Golbez
Oct 9, 2002

1 2 3!
If you want to take a shot at me get in line, line
1 2 3!
Baby, I've had all my shots and I'm fine

bobthecheese posted:

Nah, bad idea. it just makes your code difficult to maintain. If you're trying to track down where a bum value came from, you want the exception thrown when it's set, not 200 lines later, when it's trying to save.

Especially if you're dealing with large number of objects, too. Waiting 20 seconds for all the objects to get updated incorrectly, then having it fall over when it tries to save the first one, or have it fall over when it tries to update the first object incorrectly?

Since 99% of the updating will be through a web form, I was considering using something I saw on a tutorial, 'readForm', which is one command that looks at the $_POST variables and inserts them into the object. That command could contain the validation logic.

Of course, that doesn't prevent other commands from inserting directly. Hrm. I really didn't want to make getters and setters.

bobthecheese
Jun 7, 2006
Although I've never met Martha Stewart, I'll probably never birth her child.

Golbez posted:

Since 99% of the updating will be through a web form, I was considering using something I saw on a tutorial, 'readForm', which is one command that looks at the $_POST variables and inserts them into the object. That command could contain the validation logic.

Of course, that doesn't prevent other commands from inserting directly. Hrm. I really didn't want to make getters and setters.

I know it's tempting to short-cut things now, but it will only make you hate yourself later. Try to design your software (ESPECIALLY PHP software) with three things in mind:

1. I will have to change something on this in 6 months time
2. Users are idiots, and will ALWAYS manage to do everything wrong
3. Writing a few extra lines now saves several hundred extra lines later when the scope changes (or you find a bug)

Oh, and on a side note: doing a "count(*)" in mysql is always much, much faster than just pulling out all the records. You will crash your server if you try to pull out 170000 records at a time.

bobthecheese fucked around with this message at 22:58 on Mar 17, 2011

Golbez
Oct 9, 2002

1 2 3!
If you want to take a shot at me get in line, line
1 2 3!
Baby, I've had all my shots and I'm fine

bobthecheese posted:

I know it's tempting to short-cut things now, but it will only make you hate yourself later.
I'm doing this because the previous lead developer had an irrational dislike of objects. I'm hating the situation plenty already, he put me back a year in my comprehension of the subject.

quote:

Oh, and on a side note: doing a "count(*)" in mysql is always much, much faster than just pulling out all the records. You will crash your server if you try to pull out 170000 records at a time.

I haven't tried 170k at once, I have run a 170k-iteration loop to pull each one individually however. That's how I know it dies at 120k. :)

Edit: Is it sufficient to use a single __set()/__get(), and use a switch to determine what processing should be performed on it? Or do I have to go the whole route of echo $oEmployee->getSSN(); $oEmployee->setBirthdate('12/25/1999'); etc?

Golbez fucked around with this message at 23:11 on Mar 17, 2011

bobthecheese
Jun 7, 2006
Although I've never met Martha Stewart, I'll probably never birth her child.
haha. Trust MySQL to do your filtering, as much as you can. It's faster than PHP and built for it.

Also, now would probably be a good time to look at your indexes in MySQL, and see how efficient they are (if they're set up at all).

Hammerite
Mar 9, 2007

And you don't remember what I said here, either, but it was pompous and stupid.
Jade Ear Joe
Going back to revmoo's question about what the difference is between using objects and writing object-oriented code... from what I can follow (and can be bothered to follow) of Golbez's current conversation, he appears to be making an effort to be following very much an object-oriented path. All this stuff about needing an EmployeeManager object to provide Employee objects, and an Employee object having an EmployeePlan object, and another object that looks in a database and spits out Employee objects, and blah blah blah. It makes my eyes glaze over. Which is not to denigrate it, it's fine, but I don't "get it" at all. But the notion of an object as a bundle of data and functions, that models something your program is working with, I don't have any problem with.

Goethe said that "mathematicians are like Frenchmen: whatever you say to them they translate into their own language and forthwith it is something entirely different". I think that the same must be true of object-oriented programming enthusiasts.

bobthecheese
Jun 7, 2006
Although I've never met Martha Stewart, I'll probably never birth her child.
Yeah, I'm not full into OO. It has uses, and so does procedural programming. The thing is, though, that PHP software is inherently stateless, so doing full, proper OO programming is, well I won't say impossible, but... well ok I will; impossible.

The problem is that you either need a good automated ORM, and very 'dumb' objects, or you need to make intelligent objects which are their own ORM.

PHP is very flexible with how you program. You can go full procedural, even to the point where you never even write functions (doing this is retarded, but I've seen it), or you can do everything with a "Model/Resource/View" style framework, where everything is an object, and program flow is largely arbitrary. I tend to choose somewhere in the middle. Procedural with objects.

Anyway, it all depends on the project, and PHP has far worse issues than arguing over the "correct" way to use OO principals.

KuruMonkey
Jul 23, 2004

Golbez posted:

Edit: Is it sufficient to use a single __set()/__get(), and use a switch to determine what processing should be performed on it? Or do I have to go the whole route of echo $oEmployee->getSSN(); $oEmployee->setBirthdate('12/25/1999'); etc?

I want to preface this with "I don't feel strongly enough about this to tell you 'its wrong to...'" but:

I don't like code that uses data-objects. Objects, particularly in PHP, are a clumsy and awkward way to package up data that simply wants to be accessed.

Fortunately you have a far better construct in PHP; the associative array.

The "its a pain to create an object that has N attributes because I have to write N accessors and N mutators" is a symptom of this; if getX and setX is seriously all you have for the functionality of your object; don't use an object.

The PHP "overloading" misconception is that the legwork can be worked around with __get and __set is specious; any protected/private attribute that you access directly MIGHT AS WELL BE PUBLIC.

In general; making something that appears to be something else, but doesn't actually work like that something else completely, is a recipe for messy, complex and hard to maintain code. Classic example: try passing an object of a class that implements ArrayAccess to array_filter()...

(note; you CAN do interesting things with __get and __set, read only public attributes for instance, but you have a LOT of responsibility to think about what your __set should do on an error, or on a non-error refusal to update, and how the calling code (thats doing an assignment not a function call) will deal with that...)

As I said at the start though; there's a LOT of YMMV in this area.

If you're seriously rusty on how to do OO, and want to get to your feet with it; go home this weekend, load up WampServer and CodeIgniter and code up a simple blog over the weekend; hammer out all these issues on a simple system first, so you can try out different techniques and see what works before hacking on your main work project.

Golbez
Oct 9, 2002

1 2 3!
If you want to take a shot at me get in line, line
1 2 3!
Baby, I've had all my shots and I'm fine

KuruMonkey posted:

I want to preface this with "I don't feel strongly enough about this to tell you 'its wrong to...'" but:

I don't like code that uses data-objects. Objects, particularly in PHP, are a clumsy and awkward way to package up data that simply wants to be accessed.

Fortunately you have a far better construct in PHP; the associative array.

The "its a pain to create an object that has N attributes because I have to write N accessors and N mutators" is a symptom of this; if getX and setX is seriously all you have for the functionality of your object; don't use an object.

The PHP "overloading" misconception is that the legwork can be worked around with __get and __set is specious; any protected/private attribute that you access directly MIGHT AS WELL BE PUBLIC.

In general; making something that appears to be something else, but doesn't actually work like that something else completely, is a recipe for messy, complex and hard to maintain code. Classic example: try passing an object of a class that implements ArrayAccess to array_filter()...

(note; you CAN do interesting things with __get and __set, read only public attributes for instance, but you have a LOT of responsibility to think about what your __set should do on an error, or on a non-error refusal to update, and how the calling code (thats doing an assignment not a function call) will deal with that...)

As I said at the start though; there's a LOT of YMMV in this area.

If you're seriously rusty on how to do OO, and want to get to your feet with it; go home this weekend, load up WampServer and CodeIgniter and code up a simple blog over the weekend; hammer out all these issues on a simple system first, so you can try out different techniques and see what works before hacking on your main work project.

I love associative arrays, and I've been using them strongly. But I want objects mainly for the polymorphism; this app is supposed to be modified and resold to clients, and that becomes a lot easier, I think, in an OO system. 16000 lines and 200 functions doesn't necessarily seem like a lot, but it's starting to overwhelm me even at this stage. I want objects as an organizational method. Maybe my problem was jumping in to it too deep right away.

So it almost sounds like you're saying, if you're going to use basic (not hardcore) objects, might as well store the actual data in an array? So I might do, like in what you quoted, "echo $aEmployee['ssn']; $aEmployee['birthdate'] = '12/25/1999'; $oEmployees->write($aEmployee);"?

spiritual bypass
Feb 19, 2008

Grimey Drawer
I'm trying to create a little XML file and PHP is replacing the characters in my string. Google isn't giving me anything useful so far.

Why does this
php:
<?php
$out = <<<XML
<?xml version="1.0" encoding="utf-8"?>
<blah>
<etc>
</etc>
</blah>
XML;

$fh fopen('/home/rt4/sample.xml''w');
fwrite($fh$out);
fclose($fh);
produce this

code:
<XXML version="1.0" encoding="utf-8"/XXML>
<blah>
<etc>
</etc>
</blah>
and what can I do to fix it?

Lumpy
Apr 26, 2002

La! La! La! Laaaa!



College Slice

rt4 posted:

I'm trying to create a little XML file and PHP is replacing the characters in my string. Google isn't giving me anything useful so far.

Why does this
php:
<?php
$out = <<<XML
<?xml version="1.0" encoding="utf-8"?>
<blah>
<etc>
</etc>
</blah>
XML;

$fh fopen('/home/rt4/sample.xml''w');
fwrite($fh$out);
fclose($fh);
produce this

code:
<XXML version="1.0" encoding="utf-8"/XXML>
<blah>
<etc>
</etc>
</blah>
and what can I do to fix it?

What version of PHP? You code works fine on 5.3

EDIT: for fun, change your heredoc delimiter to DDD and see if that changes anything.

Lumpy fucked around with this message at 14:28 on Mar 18, 2011

bobthecheese
Jun 7, 2006
Although I've never met Martha Stewart, I'll probably never birth her child.
There SHOULDN'T be a problem with that, but I guess, potentially, <? and ?> could be causing issues, although they shouldn't because they're in a string.

Very odd. Also in the "WorksForMe" camp.

spiritual bypass
Feb 19, 2008

Grimey Drawer
Eh, I've "fixed" it by removing the XML declaration. The program that's expecting the file works fine without it :thumbsup:

butt dickus
Jul 7, 2007

top ten juiced up coaches
and the top ten juiced up players
Anyone used pcntl_fork? I have a script that would benefit from multithreading, but apparently it's a really horrible idea to do this in PHP. The manual page says that if two children processes are making queries, they might get each others' result sets, which would make attempting this worthless. If there's a way to make it work, I'll do it, otherwise I guess I'm going to have to do it in ruby.

KuruMonkey
Jul 23, 2004

Golbez posted:

I love associative arrays, and I've been using them strongly. But I want objects mainly for the polymorphism; this app is supposed to be modified and resold to clients, and that becomes a lot easier, I think, in an OO system. 16000 lines and 200 functions doesn't necessarily seem like a lot, but it's starting to overwhelm me even at this stage. I want objects as an organizational method. Maybe my problem was jumping in to it too deep right away.

So it almost sounds like you're saying, if you're going to use basic (not hardcore) objects, might as well store the actual data in an array? So I might do, like in what you quoted, "echo $aEmployee['ssn']; $aEmployee['birthdate'] = '12/25/1999'; $oEmployees->write($aEmployee);"?

My point is quite specific; if there's NO OTHER FUNCTIONALITY in a class beyond a load of get/set functions, its a waste of time using objects; assoc arrays are neater, easier to use and save you a bunch of coding.

As soon as there's meaningful validation going on, or there are fields that must be readable but non-writable, objects will get you there, and the effort's not wasted.

As a hypothetical, here's how I might implement something thats similar to your example:

php:
<?

$employees = new EmployeeModel;
// "magic" class that handles talking to the DB about employees for me

$females = $employees->getByGender('female');
// function per query in my system, maybe?
// imagine thats replaced with a function call that makes sense for your needs...
// $females can be either an array of assoc arrays
// or more likely an Iterator that produces assoc arrays

foreach($females as $female) {
  echo $female['ssn']."\n";
}
?>

Golbez
Oct 9, 2002

1 2 3!
If you want to take a shot at me get in line, line
1 2 3!
Baby, I've had all my shots and I'm fine
Yeah, in my fourth or so rewrite in 2 days, I'm now making Manager classes that pass around arrays. Added bonus: I don't have to touch 90% of my view, since that already uses the exact same arrays. And, because I already engineered this as close to OO as I could procedurally, most of the functions going into the class are straight copied from the existing code.

edit: well ugh now it just feels like i'm moving all my functions from one place to another augh why can't I figure this poo poo out

Golbez fucked around with this message at 17:07 on Mar 18, 2011

musclecoder
Oct 23, 2006

I'm all about meeting girls. I'm all about meeting guys.

Doctor rear end in a top hat posted:

Anyone used pcntl_fork? I have a script that would benefit from multithreading, but apparently it's a really horrible idea to do this in PHP. The manual page says that if two children processes are making queries, they might get each others' result sets, which would make attempting this worthless. If there's a way to make it work, I'll do it, otherwise I guess I'm going to have to do it in ruby.

I've used it with good results. Wouldn't you create a new database connection in child process so it's entirely self contained?

My script to use it was processing huge log files and getting general data from them, so race conditions weren't an issue fortunately.

butt dickus
Jul 7, 2007

top ten juiced up coaches
and the top ten juiced up players

musclecoder posted:

I've used it with good results. Wouldn't you create a new database connection in child process so it's entirely self contained?

My script to use it was processing huge log files and getting general data from them, so race conditions weren't an issue fortunately.

I would be using new connections, but the comments on the PHP manual were nebulous. A guy put a class in the comments that seems to be perfect for what I'm doing. Are you doing something similar?

McGlockenshire
Dec 16, 2005

GOLLOCKS!
I'm still a big fan of using a message/work queue instead of forking, especially when you're working with mod_php.

musclecoder
Oct 23, 2006

I'm all about meeting girls. I'm all about meeting guys.

McGlockenshire posted:

I'm still a big fan of using a message/work queue instead of forking, especially when you're working with mod_php.

True, but since he mentioned he might have to do this in Ruby, I imagined it would be on the command line.

Doctor rear end in a top hat posted:

I would be using new connections, but the comments on the PHP manual were nebulous. A guy put a class in the comments that seems to be perfect for what I'm doing. Are you doing something similar?

Thats a pretty clean implementation. Let me rip out some identifiable information and post my script here. It wasn't object oriented, just a single script.

musclecoder
Oct 23, 2006

I'm all about meeting girls. I'm all about meeting guys.
Here you go, I think I've removed any identifiable information:

php:
<?
#!/usr/bin/env php
<?php

declare(ticks=1);

if (!== $argc) {
  echo('Usage: '.$argv[0].' /path/to/logs');
  exit(1);
}

$directory realpath($argv[1]).DIRECTORY_SEPARATOR;
if (!is_dir($directory)) {
  echo($directory.' is not a valid directory.');
  exit(1);
}

// Get all of the files in the directory in an array
$files_per_process 10;
$log_files glob($directory.'*.log');
$log_files_count count($log_files);

$children_count = (int)($log_files_count/$files_per_process)+1;

$log_file_results '/tmp/log_file_parsing.results';
$log_file_results_handler fopen($log_file_results'w');

for ($i=0$i<$children_count$i++) {
  $pid pcntl_fork();
  if (-== $pid) {
    echo('Fork #'.$i.' failed.');
    exit(1);
  } elseif ($pid) {
    // Parent, let the children do it's stuff
  } else {
    // Here's a child
    $files_to_process array_slice($log_files$i*$files_per_process$files_per_process);

    foreach ($files_to_process as $log_file) {
      $log_file_handler fopen($log_file'r');
  
      $users_added 0;
      $start_time microtime(true);
      if ($log_file_handler) {
        fwrite($log_file_results_handler'Started working on file '.$log_file.PHP_EOL);
        do {
          $log_line fgets($log_file_handler);
          
          // Do the actual work on each line of the log file here.
          
        } while (!feof($log_file_handler));
      }
    
      $end_time microtime(true);
      $run_time round($end_time $start_time6);

      fwrite($log_file_results_handler'Finished working on file '.$log_file.PHP_EOL);
      fwrite($log_file_results_handler'Took '.$run_time.' seconds to run'.PHP_EOL.PHP_EOL);

      fclose($log_file_handler);
    }
    exit(0);
  }
}

// Clean everything up
pcntl_wait($status);

fclose($log_file_results_handler);

echo('Done with everything'.PHP_EOL);
exit(0);
?>
Edit: It was written to gather some information out of about 160gb of Apache logs.

Adbot
ADBOT LOVES YOU

butt dickus
Jul 7, 2007

top ten juiced up coaches
and the top ten juiced up players

musclecoder posted:

Here you go, I think I've removed any identifiable information:

Edit: It was written to gather some information out of about 160gb of Apache logs.

Thanks for this. I'll probably end up writing my own class in case I have other things that need multi-threading.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply