PHP实例化子类

4

我在尝试成为一名面向对象的程序员,所以我给自己设定了一些简单的任务。
我创建了一个类来显示给定目录中的所有图像。这很好,所以我把那个类分成了两个类:一个用于读取目录中的文件名并将它们传递到数组中,另一个用于解析该数组并显示图片。子类中的方法与其在父类中的相同(当然要用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给了你一个更好的设计,但你仍然需要改进。请参见下面的帖子以获取详细信息。 - Levi Morrison
你甚至没有考虑其他的答案。要知道,没有一个正确的设计。 - Matthieu Napoli
4个回答

5
坦白说,你的整个设计是错误的。
  1. DisplayPics不应该继承自Picfind 说实话,要么让Picfind有一个显示方法,要么让DisplayPics使用Picfind的输出结果。想一想,这样说是否合理:“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);

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


1
是的,谢谢。我一步一步地将一些过程化的东西转变成面向对象的东西,并希望最终能够得到像你那样的东西。 - erfling
好的建议,但我打算添加另一条路线。 - Levi Morrison
非常感谢。我最终做了类似的事情,但也将目录传递到文件名数组的值中,这样当我在任何其他地方调用该数组作为对象时,我可以在任何地方使用它的值。我还将解析文件扩展名的功能移动到显示方法中,以便我可以使用第一个类返回文件名数组。我想为了练习,我会将该功能分离成自己的类,并使用户可以传递参数来确定要显示哪些类型的文件。 - erfling
你可以创建一个PictureCollection,而不是一个数组,它包含了基础路径或其他所需的元信息以及图片数组。 - hakre
说实话,你正在重新创建PHP中已经定义的现有行为。请参考我的答案,其中提供了一种选项,允许您获取文件中的任何数据,包括大小、完整路径、不带名称的路径等。 - Levi Morrison
显示剩余7条评论

0

$Myclass->displayPics('./images/'); 调用了构造函数,但是没有发生任何事情。你的函数名也有拼写错误。


什么是构造函数?是否有默认的构造函数?它会是父类还是子类的构造函数? - erfling
PHP有两种构造函数的命名规范:__construct或者类名。因此,一个名为“test”的类将具有“test”作为构造函数。 - Lylo

0
我建议使用以下设计方案:
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”。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接