Couple of OO questions

It’s been quite some time since I did any serious OO programming so I’m a bit rusty.

[list=1][*]From previous OO experience in c++ I recall that you can have multiple contructors which get invoked depending on the number of parameters passed at object initialization. Should this work in PHP as I can’t seem to make it. :fangel:

[*](theory question) If I have an object of type Job that I want two different methods to print, where should these methods be placed? Say I want to be able to send to the browser as HTML or XML with printXML() and printHTML(). Should these methods be in the Job class or not?[/list]

TIA,

Matt. :slight_smile:

>>Should this work in PHP as I can’t seem to make it.
No, there is no way to have multiple contructors, actually.
But in addition it’s possible to have variable function arguments,
so it’s possible for you to define the class construnctor as:


class my_class
{
   function my_class()
   {
      $numargs = func_num_args();
      echo "Number of arguments: $numargs\
";

      // check func_get_arg and func_get_args too
   }
}

that’s what it’s possible to do actually.
I’m not telling you that’s the way to simulate multiple constructors… ;).
I’m showing that you “could”.

About question 2,
I could give an idea of what I’m doing with my classes ( work in progress…beware ).
I have an object Article which contains some information about an article.
Some methods are ( it’s not a “static class” ):
Article::getTitle()
Article::getContent()
etc
Then I have an object PageArticle ( it’s an extension of a common Page class ) that will look something like:
PageArticle::PageArticle( &$article_object ); // <<–object article
then it will have methods like
PageArticle::Show
PageArticle::ShowPrinted
PageArticle::ShowPdf

The Article is build from a class that interface to the database.

I’m elaborating these idea during these days,
so I said that just to show what it’s running in my brain…

About you I think that you could have a job class as my Article class is and then create a page class that could contain something like:

PageJob::PageJob( &$job_object )
PageJob::ShowHtml
PageJob::ShowXml

My suggestion is to have two different classes,
one for the job data and one for the page to display it.

I think that mr voostind will be able to guide you to a better solution… :wink:

:slight_smile:
pippo

How about this:
You have a Job Class, and then you have two seperate classes for printing the Job: HTML_Job_Printer and XML_Job_Printer. These two classes may have a common base class, Job_Printer.

You could then do something like this:


$job = new Job; // (you'd want to extract properties from a database or something probably)

/* For XML */
$job_printer = new XML_Job_Printer($job);
$job_printer->print();

/* For HTML */
$job_printer = new HTML_Job_Printer($job);
$job_printer->print();

In general, I think it’s always good practice to keep the code for presentation and logic separated, in separate classes for example.

Hi guys, thanks for you help. :slight_smile:

Does this make sense then?

class Job
{
	var $jobNumber ;
	var $projectManager ;
	var $office ;

	function Job( $jobNumber, $projectManager, $office )
	{
		$this->jobNumber = $jobNumber ;
		$this->projectManager = $projectManager ;
		$this->office = $office ;
	}

	function getProperties()
	{
		$returnArray = array() ;

		$returnArray['jobNumber'] = $this->jobNumber ;
		$returnArray['projectManager'] = $this->projectManager ;
		$returnArray['office'] = $this->office ;

		return $returnArray ;
	}
}

class JobPrinter_HTML
{
	var $job ;

	function JobPrinter_HTML( $job )
	{
		$this->job = $job ;
	}

	function show()
	{
		$display = array() ;
		$display = $this->job->getProperties() ;
		echo( "<p>\
" ) ;
		echo( $display['jobNumber'] . "<br />\
" ) ;
		echo( $display['projectManager'] . "<br />\
" ) ;
		echo( $display['office'] . "<br />\
" ) ;
		echo( "</p>\
" ) ;
	}
}

$test = new Job( '12345', '56789', '057' ) ;

$jobPrinter = new JobPrinter_HTML( &$test ) ;

$jobPrinter->show() ;

Matt. :slight_smile:

Hi,

I would use:


<?php
class Job
{
    var $jobNumber;
    var $projectManager;
    var $office;

    function Job( $jobNumber, $projectManager, $office )
    {
        // eventually add some check to input parameters here
        $this->jobNumber = $jobNumber;
        $this->projectManager = $projectManager;
        $this->office = $office;
    }

	function getJobNumber()
	{
		return $this->jobNumber;
	}

	function getProjectManager()
	{
		return $this->projectManager;
	}

	function getOffice()
	{
		return $this->office;
	}
}

class JobHTML
{
    function Show( &$job )
    {
        echo( "<p>\
" ) ;
        echo( $job->getJobNumber() . "<br />\
" ) ;
        echo( $job->getProjectManager() . "<br />\
" ) ;
        echo( $job->getOffice() . "<br />\
" ) ;
        echo( "</p>\
" ) ;
    }
}

$test = new Job( '12345', '56789', '057' );

JobHTML::Show( $test ) ;

?>

So it’s better to access properties using a function foreach propertie instead of a function that returns an array of properties.

About the way of how to display the data,
I’m not sure 100% that’s correct what I wrote.
you have to try to put all the pieces of the puzzle togheter.

:slight_smile:
pippo

Ok, I’m all for OO, but surely your class is just a class for class’ sake?

In this particular example, pippo’s code works very well. However, in larger (more real-life) problems, a static class won’t work. Reason: inheritance.

Showing a job can be done to many different outputs (HTML/XML/PDF) but all outputs have things in common, like some sort of header, the showing of the job number, or some footer. But you don’t want this to be visible to the outside world. Normally, you solve this by writing a base class that implements all important parts, and a single method that calls all other methods in the right order. Subclasses (special viewers) override only those methods that need it. For example:


class JobPrinter
{
    function JobPrinter(&$job)
    {
        $this->job =& $job;
    }
    
    function show()
    {
        $this->showHeader();
        $this->showJobNumber();
        $this->showProjectManager();
        $this->showOffice();
    }
    
    function showHeader()
    {
    }
    
    function showJobNumber()
    {
        echo $this->job->getJobNumber();
    }
    
    function showProjectManager()
    {
        echo $this->job->getProjectManager();
    }
    
    function showOffice()
    {
        echo $this->job->getOffice();
    }
    
    function showFooter()
    {
    }
}

function HtmlJobPrinter extends JobPrinter
{
    function showHeader()
    {
        echo "<p>\
";
    }
    
    function showJobNumber()
    {
        parent::showJobNumber();
        echo "<br />\
";
    }
    
    function showProjectManager()
    {
        parent::showProjectManager();
        echo "<br />\
";
    }
    
    function showOffice()
    {
        parent::showOffice();
        echo "<br />\
";
    }
    
    function showFooter()
    {
        echo "</p>\
";
    }
}

The various show…-methods (except for show() itself) are protected methods. Subclasses may call and/or override them, but for classes using a job printer, they should be invisible. So code using the HtmlJobPrinter above would only do this:


$printer =& new HtmlJobPrinter($job);
$printer->show();

In the above example, a class with only static methods certainly won’t work.

There is another issue with the current design of jobs and printing them. To me it makes sense that a job knows how to print itself in some way. You might want to print specific information not available through get-methods for example. A Job instance is the only object that knows everything about a specific job, so I think it would be logical that the class Job has a method show(). (Note: this is just a minor issue, so don’t think too much about it.) But how can class Job have a method show, if it doesn’t know which kind of output it should produce? The solution here is to move the method ‘show()’ from class JobPrinter to class Job, like this:


class Job
{
    function show(&$printer)
    {
        $printer->showHeader();
        $printer->showJobNumber($this->jobNumber);
        $printer->showProjectManager($this->projectManager);
        $printer->showOffice($this->office);
        $printer->showFooter();
    }
}

This solution has some advantages:

  • A job knows how to show itself. As I said: to me that makes more sense than the other way around. But this is just a personal taste.
  • A printer can be reused to show other jobs. Previously a printer was instantiated specifically for one job, which seems (to me again) a bit strange. Now you can instantiate a printer once, and use it again and again for different jobs.

On the other hand, there are is a disadvantage a well:

  • All methods in the JobPrinter classes that used to be protected are now public, so the nice encapsulation is gone. (No more: ‘$printer->show()’);

So which design is better? I don’t know. It’s a matter of taste, and of what makes more sense to you as a designer. But note that going from one solution to the other can easily be done without changing to much of the code. So if you’re not happy with some solution after all, you can always modify the code to use another. The steps taken are not that hard.

Vincent

Many thanks for popping over to reply Vincent. :slight_smile:

Just so I know I’ve got your second method right in my head, the 2 classes cross reference each other yes?

In what order would I then have to create objects? Create a job object (say $testJob), create a jobPrinterHTML object (say $jobPrinter), call my $testJob->show( $jobPrinter ). Then I can create another job object (say $testJob2), but can I call $testJob2->show( $jobPrinter ) ?? Isn’t $jobPrinter associated with $testJob already?

Thanks. :fangel: :weyes: :sick: :badpc: :wacko: :smiley:

And if I were to use the first version, should I destroy the $job and $printer objects after printing, or will overwriting them with the next job and printer objects be sufficient?

Double thanks. :smiley:

Just so I know I’ve got your second method right in my head, the 2 classes cross reference each other yes?

I’m sorry, but no :slight_smile:

Cross-references between classes are certainly possible, but if you don’t really need them, you might get sorry if you do.

In the second coding example, you’ll see that the various methods are called on the printer ($printer->showHeader()), and that each method is passed the information it needs (the job number, the project manager). So in this case, the printer know nothing about the job it’s showing.

You still can use a cross-reference (passing the full job object to some show-method), but you don’t want to pass the job on construction of the printer, or else you can’t use the printer multiple times.

Say you have two jobs ($job1 and $job2) and you want them both printed. You can do that like this:


// Given are $job1 and $job2
$printer =& new HtmlJobPrinter;
$job1->show($printer);
// $printer->newPage(); (or something)
$job2->show($printer);

Like I said. This is just another solution. I can’t say this one is better than the other. Both have their pros and cons!

Vincent

Isn’t the parent class jobPrinter wanting to be passed a job when it’s created though? As this constructor isn’t overwritten in the HTML child class, what does it do?

Thanks. :slight_smile:

The JobPrinter base class can look like this:


class JobPrinter
{
    function JobPrinter()
    {
    }

    function showJobNumber($number)
    {
        echo $number;
    }

    // ...
}

If you were to pass a Job object on construction, you’d have to assign the job object to a member variable of the JobPrinter, binding instances of that class tightly to a single instance of a Job. By NOT doing that, it is easier to reuse a JobPrinter for different classes.

Vincent

Thanks so much for your help. :slight_smile:

So, just to make sure I’ve got this now, the pros and cons of each method are:

Method 1

Pros:

[list][]Better encapsulation
[
]Simpler to understand classes[/list]
Cons:

[list][]Each job class needs it’s own jobPrinter object
[
]Job is unaware of how to print itself[/list]

Method 2

Pros:

[list][]Only need to create one instance of any type of jobPrinter object
[
]Job objects are aware of how to print themselves[/list]
Cons:

[list][]Job objects are still reliant on having a suitable JobPrinter object so they can print themselves (Job class on it’s own is lost without it’s sister classes)
[
]Encapulation is lost.[/list]

I think the jury is out for me at the moment as to which is best. I’m tending to prefer method one, but I’m not so keep on the printer objects having to be created each time (bit of a resourse waste?).

Thanks again,

Matt. :slight_smile:

A second advantage of the first solution is that the Printer classes are more flexible. Subclasses can override the method ‘show()’, and can add more methods or change the order in which the other methods are called. In the second solution the Job itself defines the way it is printed (with all possible printers).

Which solution is best remains a bit unclear. But remember that it’s easy to switch solutions, even when the rest of the program is already written! And all thanks to OO :).

Vincent

I was just tthinking of another version of this.

What is your HTMLJobPrinter object didn’t take a job object reference on instanciation, but rather one was passed to it at render time.

class HTMLJobPrinter extends JobPrinter
{
  function HTMLJobPrinter
  {
  }

  function display( &$job )
  {
    //blah blah
  }
}

Any thoughts on this method Vincent?

Well, I’m not Vincent, but I can give you my thoughts on this :smiley:

I think it’s a good idea, since that way you can use one instance of HTMLJobPrinter to print many Job objects. Suppose you’d want to print 10 jobs, do you want to instanciate 10 HTMLJobPrinter objects then?? I think not. Using one HTMLJobPrinter and then passing its display() method the Job object each time is a better solution if you ask me.

Thanks mate. All input greatly appreciated. :slight_smile:

I was wondering how this compares to Vincent’s second method (passing a printer object to the classes own display method).

Personally I think I prefer this method, as you can have better encapulation, but still have reusable printer objects.

Not requiring a Job to be passed on construction indeed allows the printer to be used for multiple jobs. So that’s a plus. The drawback of this approach clearly is that the class now becomes a module of functions instead of a ‘component’: the job being printed has to be passed to every method called from the display-method.

As always, it depends on the rest of the program which design fits you best. If instantiating a new printer for every job costs little, there is no real problem in doing so. If, on the other hand, the constructor of the printer class does a lot of work (not specific to some job), then it can be a good idea to allow printer-objects to be reused for different jobs.

There is no ‘best’ design. There are good designs and designs that work a little better. Of course there are also bad designs, but these are often easy to spot, once you know where to look.

Vincent