【问题标题】:PHP instantiating child classPHP实例化子类
【发布时间】:2011-12-31 15:28:30
【问题描述】:

我正在努力成为一名面向对象的编码员,所以我给自己一些简单的任务。
我构建了一个显示给定目录中所有图像的类。效果很好,所以我将该类分为两个类,一个用于读取目录中的文件名并将它们传递给一个数组,另一个用于解析该数组并显示图片。子类中的方法与父类中的方法完全相同(当然除了用 parent:: 代替 this->)。

现在,当我实例化子类并调用它的方法时,似乎什么都没有发生。

类:

class Picfind
{
   public function findPics($dir){
       $files = array();
       $i=0;
       $handle = opendir($dir);
       while (false !== ($file = readdir($handle))){
           $extension = strtolower(substr(strrchr($file, '.'), 1));
           if($extension == 'jpg' || $extension == 'gif' || $extension == 'png'){
                // now use $file as you like
                $i++;
                $files['file' . $i] = $file;
           }
       }
       return $files;
    }
}

class DisplayPics extends Picfind
{

    function diplayPics($dir) 
    {
        echo 'displayPics method called';

        foreach(parent::findPics($dir) as $key => $val) {
            echo '<img src="' . $dir . $val . '" img><br/>';
        }
    }
}

实例化:

include("class.picFind.php");
$Myclass = new DisplayPics();
$Myclass->displayPics('./images/');

【问题讨论】:

  • 你的整个设计都错了。虽然 hakre 确实为您提供了更好的设计,但您仍然可以使用一些改进。有关详细信息,请参阅下面的帖子。
  • 您甚至没有考虑其他答案。知道没有一个正确的设计。

标签: php class parent instantiation


【解决方案1】:

说实话:你的整个设计都是错误的。

  1. DisplayPics 不应该从Picfind 继承。 老实说,要么让Picfind 有一个显示方法,要么让DisplayPicsPicfind 获取输出。想想,以下是否有意义:“DisplayPics 是 PicFind。”?如果不是,那可能是错误的。
  2. 类通常不是动词。 更好的名称是Pictures,带有finddisplay 方法。在您的情况下,您在目录中找到了一些东西,这导致了下一点:
  3. 您应该使用 PHP DirectoryIterator 类。这样,您可以对找到的文件做任何您想做的事情。您将获得有关该文件的所有信息,并且它与 PHP 完美集成。
  4. 您需要分离关注点。 这就是 hakre 建议的全部内容。减少依赖和解耦通常很有帮助。

/**
 * ExtensionFinder will find all the files in a directory that have the given
 * extensions.
 */
class ExtensionFinder extends DirectoryIterator {
    
    protected $extensions =  array();
    
    public function __contruct($directory) {
        parent::__construct($directory);
        
    }
    
    /**
     * Sets the extensions for the iterator. 
     * @param array $extensions The extensions you want to get (without the dot).
     */
    public function extensions(array $extensions) {
        $this->extensions = $extensions;
    }
    
    /**
     * Determines if this resource is valid.  If you return false from this 
     * function, the iterator will stop.  
     * @return boolean Returns true if the value is a file with proper extension.
     */
    public function valid() {
        if (parent::valid()) {
            $current = parent::current();
            
            if ($current->isFile()) {
                // if the extensions array is empty or null, we simply accept it.
                if (empty($this->extensions)) {
                    //otherwise filter it
                    if (in_array($current->getExtension(), $this->extensions)) {
                         return true;
                    } else {
                        parent::next();
                        return $this->valid();
                    }
                } else {
                    return true;
                }
            } else {
                parent::next();
                return $this->valid();
            }
        } else {
            return false;
        }
        
    }
}

class PictureFinder extends ExtensionFinder {
    public function __construct($directory) {
        parent::__construct($directory);
        
        $this->extensions = array (
            'jpg',
            'gif',
            'png'
        );
    }
}

使用方法:

$iterator = new PictureFinder('img/');
foreach($iterator as $file) {
    //do whatever you want with the picture here.
    echo $file->getPathname()."\n";
}    

请注意,您可以使用我在上面定义的ExtensionFinder 类来查找任何扩展名的文件。这可能比简单地查找图像更有用,但我为该特定用例为您定义了一个 PictureFinder 类。

【讨论】:

    【解决方案2】:

    您写道,您想学习面向对象编程。以下内容呢:

    class PicFinder
    {
       /**
        * @return array
        */
       public function inDirectory($directory)
       {
           return // array of files
       }
    }
    
    class PicPresentation
    {
        public function present(array $pictures)
        {
            // your presentation code
        }
    }
    
    
    $path = '/your/path';
    $datasource = new PicFinder();
    $presentation = new PicPresentation();
    $pictures = $datasource->inDirectory($path);
    $presentation->present($pictures);
    

    保持分离和松散耦合。一个对象应该对一件事负责,例如一个对象从目录中获取图片列表,另一个对象用于演示。祝你好运!

    【讨论】:

    • 好的,谢谢。我一步一步地把一些程序化的东西变成了面向对象的东西,并希望最终得到像你那样的东西。
    • 好建议,但我要添加另一条路线。
    • 非常感谢。我最终做了一些非常相似的事情,但也将目录传递到我的文件名数组中的值中,这样当我将该数组作为其他任何地方的对象调用时,我可以在任何地方使用它的值。我还将解析文件扩展名的功能移到了 display 方法中,这样我就可以使用第一个类返回一个文件名数组。我想作为实践,我也会将该功能分离到它自己的类中,并使其用户可以传递一个参数来确定将显示哪些类型的文件。
    • 您可以创建一个PictureCollection,而不是数组,在图片数组旁边包含该基本路径或您需要的任何其他元信息。
    • 老实说,您正在重新创建已经在 PHP 中定义的现有行为。请参阅我的答案以获取允许您从文件中获取任何数据的选项,包括大小、完整路径、不带名称的路径等。
    【解决方案3】:

    $Myclass->displayPics('./images/'); 正在调用构造函数,但什么也没有发生。 你的函数名也有错别字。

    【讨论】:

    • 什么构造函数?默认有构造函数吗?是父类还是子类的构造函数?
    • php 有 2 个构造函数约定。 __construct 或类名。所以一个名为'test'的类将有一个'test'的构造函数
    【解决方案4】:

    我建议改为:

    class PicFinder
    {
        public function findPics($dir){
           ...
        }
    }
    
    class PicDisplayer
    {
        protected $picFinder;
    
        public function __construct() {
            // Default pic finder
            $this->setPicFinder(new PicFinder());
        }
    
        public function diplayPics($dir)  {
            echo 'displayPics method called';
    
            foreach($this->getPicFinder()->findPics($dir) as $key => $val) {
                echo '<img src="' . $dir . $val . '" img><br/>';
            }
        }
    
        protected function setPicFinder(PicFinder $picFinder) {
            $this->picFinder = $picFinder;
        }
        protected function getPicFinder() {
            return $this->picFinder;
        }
    }
    

    这样您就只使用 PicDisplayer 而不关心它是如何找到图片的。但是如果需要,您仍然可以通过扩展 PicFinder 类并实现特定行为来更改“PicFinder”。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-25
      • 2023-03-30
      相关资源
      最近更新 更多