PHP初学者OOP构建一个对象

Sup*_*nja 4 php

在此先感谢您的帮助和指导.我终于完成了从线性编程到OOP的转换.我正在上第一堂课,我可以用一点方向.我的第一堂课是一个具有以下属性的画廊

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;
}
Run Code Online (Sandbox Code Playgroud)

因此我的出局看起来像:

Gallery Object
(
    [galleryID] => 
    [galleryName] => 
    [clientName] => 
    [bg_color] => 
    [albumAgreement] => 
    [maxChanges] => 
    [sharing_on] => 
    [revisions] => 
)
Run Code Online (Sandbox Code Playgroud)

我的下一步是我想将'revisions'作为一个对象,以便我的输出看起来像

Gallery Object
(
    [galleryID] => 
    [galleryName] => 
    [clientName] => 
    [bg_color] => 
    [albumAgreement] => 
    [maxChanges] => 
    [sharing_on] => 
    [revisions] => Revisions Object (
        [revisionID] =>
        [revisionName] =>
    )
)
Run Code Online (Sandbox Code Playgroud)

我有什么方向可以选择这样的课程以及课程的样子?

谢谢

rdl*_*rey 22

这更像是一个长篇评论,因为它解释了你的困境的根源,但没有提供任何解决方案.

OOP第1课:仅仅因为你正在使用类并不意味着你正在编写面向对象的代码.

对象中的公共属性很少有很好的用例.让我们看一下OP的例子:

class Gallery {
    public $galleryID;
    public $galleryName;
    // ...
}
Run Code Online (Sandbox Code Playgroud)

定义了我们的属性后public,以下两个代码片段有何不同?

$gallery = new Gallery;
$gallery->galleryId = 42;
$gallery->galleryName = 'some name';

// vs:

$gallery = array(
    'galleryId' => 42,
    'galleryName' => 'some name'
);
Run Code Online (Sandbox Code Playgroud)

如果你说,"它们根本没有什么不同",那么你就是对的.实际上,由于涉及的实例化开销,基于对象的代码将更慢new.还有一些其他因素,例如能够传递对象的引用而不是复制新数组,但这些因素不会影响这种特定情况.

OOP第2课:对象是一个黑盒子

创建一个只是可变属性集合的对象的问题是,其余代码完全了解该对象内部发生的事情.我们来谈谈为什么这很糟糕......

在复杂性方面,人类只是不太好.良好的软件旨在通过将功能封装到离散单元中来最小化复杂性.在这种情况下,我们希望将"gallery"实体的所有逻辑封装到Gallery类中.这是域驱动设计(DDD)方法的一部分.我们想要做的就是隔离Gallery外界世界; 我们希望它的内部实现对我们的其余代码不透明.我们应用程序的其余部分不应该知道或关心Gallery函数如何,只是它按预期工作.这里的额外好处是我们可以专注于使画廊按照预期工作然后忘记它.我们不会被记住如何Gallery与a Image或a 一起工作Revision.这种松耦合是OO设计中最强大的工具之一.

虽然它可能在非常小的范围内工作,但是不可能同时保持整个应用程序的逻辑.无论你有多聪明,我们的大脑都没有足够的RAM.

回到代码,如果我们的应用程序代码知道如何Gallery为自己分配名称,那么我们已经允许"gallery-ness"的逻辑泄漏到程序的其余部分.当我们决定在分配时验证新的图库名称时会发生什么?我们现在必须在我们指定图库名称的代码中随处放置验证逻辑,因为我们没有关于"gallery-ness"抽象概念的所有内容.更好的设计是Gallery在对象本身内封装属性的赋值:

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

如果我们以这种方式构建我们的类,当我们需要为库指定名称时,我们总是只有一个入口点.现在,当我们对画廊的要求发生变化时(他们会),我们所有的应用程序代码 - 与图库名称分配背后的逻辑无关 - 都与破损隔离开来.我们只需在名称设置器中添加一个新方法,并在程序中创建最小的剧变:

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

解决OP问题

要回答如何将封装Revision对象表示为更高级别Gallery实例的属性的问题,我们需要一些上下文.看来OP正在尝试做的是模型域实体,它将被写入后端持久层(例如数据库,平面文本文件等)并从中检索.

贫血领域模型是处理这种情况的一种方式,但它通常被认为是反模式.马丁福勒写道:

贫血领域模型的基本症状是乍一看它看起来像真实的东西.有许多对象,其中许多以域空间中的名词命名,并且这些对象与真实域模型具有的丰富关系和结构相关联.当你看到这个行为时会发现这个问题,你会发现这些物体上几乎没有任何行为,这使得它们只不过是吸气剂和制定者的一部分.实际上,这些模型通常都带有设计规则,表明您不要将任何域逻辑放在域对象中.相反,有一组服务对象捕获所有域逻辑.这些服务位于域模型之上,并使用域模型进行数据.

考虑到这些参数,您应该考虑使用类似DataMapperGateway模式的东西来处理需要持久化到某种形式的后端存储的域对象.

备择方案

让我们忘记Revision一分钟的对象,并想象我们想要使用一个Slideshow对象来输出图库中的图像.这个类看起来像:

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

忽略这样一个事实,即PHP代码实际上不会用于"播放"幻灯片,因为这会在客户端代码中发生.这里重要的Slideshow是使用Composition来访问Gallery.这种结构大大优于直接new荷兰国际集团一Gallery内部Slideshow原因:

  1. Slideshow是可拔插的-我们可以插入遵循"画廊性"的概念,任何对象(通常Gallery会被宣布为符合特定接口契约).

  2. Slideshow现在迫切测试.我们如何处理Gallery提供的图像类型不合适的情况?如果我们直接在实例化Gallery内部,Slideshow我们无法模拟这样的条件.通过注入Slideshow我们的依赖关系,我们有机会测试代码处理不同操作条件的能力.

当然,有时直接实例化另一个类中的对象是合适的.有关这个主题的更多指导,我建议MiškoHevery在他的文章To"new"或不是"new"中提出建议.


xbo*_*nez 10

好的是PHP是动态类型的,所以你的代码几乎保持不变.初始化时revisions,只需将其初始化为Revisions对象的实例,就像这样

$gallery = new Gallery();
$gallery->revisions = new Revisions()  // assuming you have defined the Revisions class
Run Code Online (Sandbox Code Playgroud)

至于类应该是什么样的,基于你的var_dump,像这样:

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

}
Run Code Online (Sandbox Code Playgroud)

由于revisions你的问题并不完全清楚,你可能想要创建一个Revision对象而不是Revisions(不是复数),然后$gallery->revisions成为一个数组Revision.