PHP Beginner OOP Object Creation

Thank you in advance for your help and guidance. I am finally making the transition from linear programming to OOP. I am working on my first class and I could use a little direction. My first class is a gallery with the following properties

class Gallery { //Gallery Name public $galleryID; public $galleryName; //Client Name public $clientName; //Gallery Options public $bg_color; public $albumAgreement; public $maxChanges; public $sharing_on; //Revisions public $revisions; } 

My output looks like this:

 Gallery Object ( [galleryID] => [galleryName] => [clientName] => [bg_color] => [albumAgreement] => [maxChanges] => [sharing_on] => [revisions] => ) 

The next step I would like to make “revisions” is also an object, so that my output looks like

 Gallery Object ( [galleryID] => [galleryName] => [clientName] => [bg_color] => [albumAgreement] => [maxChanges] => [sharing_on] => [revisions] => Revisions Object ( [revisionID] => [revisionName] => ) ) 

In what direction will I be doing something like this and what might the class look like?

thanks

+4
source share
4 answers

It's good that PHP is dynamically typed, so your code stays pretty much the same. When you initialize revisions , just initialize it as an instance of the revisions object, like this

 $gallery = new Gallery(); $gallery->revisions = new Revisions() // assuming you have defined the Revisions class 

As the class should look, based on your var_dump, something like this:

 class Revisions { public $revisionID; public $revisionName; public function __construct($id, $name) { $this->revisionID = $id; $this->revisionName = $name; } // if required, define a default constructor as well that does not take any parameters } 

Since what revisions does not quite clear from your question, you can make a Revision object instead of a revisions (rather than a plural) and then $gallery->revisions be an array of Revision .

+10
source

This is more of a long form commentary as it explains the origin of your dilemma, but does not provide any solutions.

OOP Lesson 1: Just because you use classes does not mean that you write object-oriented code.

Your facilities rarely use a good precedent for public property. Consider the OP example:

 class Gallery { public $galleryID; public $galleryName; // ... } 

By defining our properties as public , how do the following two code fragments differ?

 $gallery = new Gallery; $gallery->galleryId = 42; $gallery->galleryName = 'some name'; // vs: $gallery = array( 'galleryId' => 42, 'galleryName' => 'some name' ); 

If you said, "they are not at all completely different," then you will be right. In fact, object code will be slower due to creation overhead associated with new . There are other factors, such as the ability to pass references to an object instead of copying a new array, but this does not affect this particular situation.

OOP Lesson 2: Objects Are a Black Box

The problem with creating an object that is nothing more than a set of mutable properties is that the rest of your code has a complete picture of what is going on inside that object. Tell us why this is bad ...

People are just not very good when it comes to complexity. Good software aims to minimize complexity by encapsulating functionality in separate blocks. In this case, we want to encapsulate the entire logic of the gallery object in the Gallery class. This makes sense in a domain-based approach (DDD). What we want to do is the Gallery wall from the outside world; we want its internal implementation to be opaque to the rest of our code. The rest of our application does not need to know or care about how Gallery functions, just how it works. An added benefit here is that we can focus on making the gallery work as it should, and then forget about it. We don’t have to remember how Gallery works with Image or Revision . This loose connection is one of the most powerful tools in OO design.

While this can work on very small scales, it is not possible to simultaneously store the logic of an entire application in your head. No matter how smart you are, our brains just don't have enough RAM.

Returning to the code, if our application code knows how Gallery takes its name, we already assumed that the gallery-ness logic had leaked to the rest of the program. What happens when we decide that we want to check new gallery names when they are assigned? Now we have to put this validation logic everywhere in our code, where we indicated the names of the galleries, because we were not shy about the whole abstract concept of “gallery”. A much better design would be to encapsulate the assignment of Gallery properties within the object itself:

 class Gallery { private $galleryId; private $name; public function setName($name) { $this->name = $name; } public function getName($name) { return $this->name; } } 

If we structure our class this way, we will always have one entry point when we need to assign a name to the gallery. Now that our gallery requirements are changing along the way ( and they will ), all of our application code, which is blind to the gallery naming logic, is isolated from breakage. We simply add a new method to our set of names and create minimal upheaval in our program:

 class Gallery { private $galleryId; private $name; public function setName($name) { $this->validateName($name); $this->name = $name; } private function validateName($name) { if (!preg_match('/^[az]+$/', $name)) { throw new Exception; } } public function getName($name) { return $this->name; } } 

OP Addressing

To answer the question of how to represent an encapsulated Revision object as a property of a higher-level Gallery instance, we need a little context. It seems that what the OP is trying to do is model the entities of the domain that will be written to and retrieved from the level of ongoing support (for example, a database, a flat text file, etc.).

Anemic domain models are one way to handle this, however it is usually considered an anti-pattern. Martin Fowler writes:

The main symptom of the anemic domain model is that with the first blush it looks like the real thing. There are objects, many of which are named in nouns in the domain space, and these objects are associated with the rich relationships and structure that real domain models have. The catch comes when you look at the behavior, and you understand that there is practically no behavior on these objects, making them a little larger than bags with getters and setters. In fact, often these models come with design rules that say that you should not introduce any domain logic into domain objects. Instead, there is a set of service objects that capture the entire domain logic. These services live on top of the domain model and use the domain model for data.

Given these arguments, you should use something like DataMapper or Gateway to work with domain objects that need to be stored in some form of backend memory.

Alternatives

Forget about the Revision object for a minute and imagine that we want to use the Slideshow object to display images from the gallery. This class might look like this:

 class Slideshow { private $gallery; public function __construct(Gallery $gallery) { $this->gallery = $gallery; } public function play() { // do something with the gallery here } } 

Ignore the fact that the PHP code will not actually be used to “play” the slide show, like what will happen in the client code. The important thing is that Slideshow uses Composition to access Gallery . This design is significantly superior directly to the new ing a Gallery inside Slideshow , because:

  • Now Slideshow connected - we can insert any object that follows the concepts of "gallery-ness" (usually Gallery will be declared in accordance with the specified interface contract).

  • Now Slideshow can be checked. How do we handle a situation in which Gallery does not have the appropriate image types? If we directly create a Gallery instance inside a Slideshow , we cannot imitate such conditions. By introducing Slideshow dependencies, we allow us to test the ability of the code to handle various working conditions.

Of course, sometimes he needs to directly create an instance of an object inside another class. For more information on this topic, I would advise Mishko Hevery in my article "New" or not "new . "

+22
source

Essentially, you create a separate class for Revisions , just like for Gallery .

 class Gallery { //Gallery Name public $galleryID; public $galleryName; //Client Name public $clientName; //Gallery Options public $bg_color; public $albumAgreement; public $maxChanges; public $sharing_on; //Revisions public $revisions; } class Revisions { public $revisionID; public $revisionName; } //Set the revisions within gallery $gallery = new Gallery(); $gallery->revisions = new Revisions(); 
0
source

Do some research on setters and getters or constructors. I will give an example using each below, which has the same end result.

 class Gallery { //Gallery Name protected $galleryID; protected $galleryName; //Client Name protected $clientName; //Gallery Options protected $bg_color; protected $albumAgreement; protected $maxChanges; protected $sharing_on; //Revisions protected $revisions; public function setGalleryID($id) { $this->galleryID = $id; } public function getGalleryID() { return $this->galleryID; } public function setRevisions(Revisions $revisions) { $this->revisions = $revisions; } public function getRevisions() { return $this->revisions; } } $gallery = new Gallery(); $gallery->setRevisions(new Revisions()); var_dump($gallery->getRevisions()); 

Or using the constructor

 class Gallery { //Gallery Name protected $galleryID; protected $galleryName; //Client Name protected $clientName; //Gallery Options protected $bg_color; protected $albumAgreement; protected $maxChanges; protected $sharing_on; //Revisions protected $revisions; public function __construct($id, Revisions $revisions) { $this->galleryID = $id; $this->revisions = $revisions; } public function getGalleryID() { return $this->galleryID; } public function getRevisions() { return $this->revisions; } } $gallery = new Gallery(1, new Revisions()); var_dump($gallery->getRevisions()); 

That way, you have more control over what happens, what comes out, what is read-only (gettable), write-only (configurable), or both. For example, in the installer, you can see that Revision is written before $ revision. This ensures that only the Revisions object can be set to $ this-> revisions.

0
source

Source: https://habr.com/ru/post/1446526/


All Articles