Php:学习OOP,静态与常规方法

Php:学习OOP,静态与常规方法,php,class,oop,object,methods,Php,Class,Oop,Object,Methods,这是我在堆栈溢出中的第一篇帖子,如果我不遵守任何规则,请容忍我。我用php编写脚本已经有一段时间了,但实际上从未使用过它的OOP端。我一直在网上做一个培训课程(不确定我是否大声说出是哪一个是因为版权?) 无论哪种方式,在程序员在他的一个类中创建了一些静态方法的过程中,我决定我不想让我的方法成为静态的。下面是他写的代码。我做了同样的事情,只是对代码中的变量引用不同,比如$this->variable `<?php // If it's going to need the database,

这是我在堆栈溢出中的第一篇帖子,如果我不遵守任何规则,请容忍我。我用php编写脚本已经有一段时间了,但实际上从未使用过它的OOP端。我一直在网上做一个培训课程(不确定我是否大声说出是哪一个是因为版权?)

无论哪种方式,在程序员在他的一个类中创建了一些静态方法的过程中,我决定我不想让我的方法成为静态的。下面是他写的代码。我做了同样的事情,只是对代码中的变量引用不同,比如$this->variable

`<?php
// If it's going to need the database, then it's 
// probably smart to require it before we start.
require_once(LIB_PATH.DS.'database.php');

class Photograph extends DatabaseObject {

    protected static $table_name="photographs";
    protected static $db_fields=array('id', 'filename', 'type', 'size', 'caption');
    public $id;
    public $filename;
    public $type;
    public $size;
    public $caption;

    private $temp_path;
  protected $upload_dir="images";
  public $errors=array();

   protected $upload_errors = array(
        // http://www.php.net/manual/en/features.file-upload.errors.php
        UPLOAD_ERR_OK               => "No errors.",
        UPLOAD_ERR_INI_SIZE     => "Larger than upload_max_filesize.",
       UPLOAD_ERR_FORM_SIZE     => "Larger than form MAX_FILE_SIZE.",
       UPLOAD_ERR_PARTIAL       => "Partial upload.",
       UPLOAD_ERR_NO_FILE       => "No file.",
      UPLOAD_ERR_NO_TMP_DIR => "No temporary directory.",
      UPLOAD_ERR_CANT_WRITE => "Can't write to disk.",
      UPLOAD_ERR_EXTENSION  => "File upload stopped by extension."
    );

     // Pass in $_FILE(['uploaded_file']) as an argument
  public function attach_file($file) {
        // Perform error checking on the form parameters
        if(!$file || empty($file) || !is_array($file)) {
          // error: nothing uploaded or wrong argument usage
          $this->errors[] = "No file was uploaded.";
          return false;
         } elseif($file['error'] != 0) {
          // error: report what PHP says went wrong
          $this->errors[] = $this->upload_errors[$file['error']];
          return false;
        } else {
            // Set object attributes to the form parameters.
          $this->temp_path  = $file['tmp_name'];
          $this->filename   = basename($file['name']);
          $this->type       = $file['type'];
          $this->size       = $file['size'];
            // Don't worry about saving anything to the database yet.
             return true;

         }
    }

    public function save() {
        // A new record won't have an id yet.
        if(isset($this->id)) {
            // Really just to update the caption
            $this->update();
        } else {
            // Make sure there are no errors

            // Can't save if there are pre-existing errors
          if(!empty($this->errors)) { return false; }

            // Make sure the caption is not too long for the DB
          if(strlen($this->caption) > 255) {
                $this->errors[] = "The caption can only be 255 characters  long.";
                return false;
            }

          // Can't save without filename and temp location
          if(empty($this->filename) || empty($this->temp_path)) {
            $this->errors[] = "The file location was not available.";
            return false;
          }

            // Determine the target_path
          $target_path = SITE_ROOT .DS. 'public' .DS. $this->upload_dir .DS. $this->filename;

          // Make sure a file doesn't already exist in the target location
          if(file_exists($target_path)) {
            $this->errors[] = "The file {$this->filename} already exists.";
            return false;
          }

            // Attempt to move the file 
            if(move_uploaded_file($this->temp_path, $target_path)) {
            // Success
                 // Save a corresponding entry to the database
                if($this->create()) {
                    // We are done with temp_path, the file isn't there anymore
                     unset($this->temp_path);
                    return true;
                }
            } else {
                // File was not moved.
             $this->errors[] = "The file upload failed, possibly due to incorrect permissions on the upload folder.";
             return false;
            }
        }
    }

    public function destroy() {
        // First remove the database entry
        if($this->delete()) {
            // then remove the file
           // Note that even though the database entry is gone, this object 
            // is still around (which lets us use $this->image_path()).
              $target_path = SITE_ROOT.DS.'public'.DS.$this->image_path();
            return unlink($target_path) ? true : false;
        } else {
            // database delete failed
            return false;
        }
    }
     public function image_path() {
       return $this->upload_dir.DS.$this->filename;
    }

     public function size_as_text() {
        if($this->size < 1024) {
            return "{$this->size} bytes";
        } elseif($this->size < 1048576) {
            $size_kb = round($this->size/1024);
            return "{$size_kb} KB";
        } else {
            $size_mb = round($this->size/1048576, 1);
            return "{$size_mb} MB";
        }
    }


// Common Database Methods
public static function find_all() {
    return self::find_by_sql("SELECT * FROM ".self::$table_name);
  }

  public static function find_by_id($id=0) {
      global $database;
    $result_array = self::find_by_sql("SELECT * FROM ".self::$table_name."  WHERE id=".$database->escape_value($id)." LIMIT 1");
        return !empty($result_array) ? array_shift($result_array) : false;
  }

  public static function find_by_sql($sql="") {
     global $database;
    $result_set = $database->query($sql);
    $object_array = array();
    while ($row = $database->fetch_array($result_set)) {
       $object_array[] = self::instantiate($row);
    }
        return $object_array;
  }

    private static function instantiate($record) {
    // Could check that $record exists and is an array
$object = new self;
    // Simple, long-form approach:
    // $object->id              = $record['id'];
    // $object->username    = $record['username'];
    // $object->password    = $record['password'];
    // $object->first_name = $record['first_name'];
    // $object->last_name   = $record['last_name'];

    // More dynamic, short-form approach:
    foreach($record as $attribute=>$value){
      if($object->has_attribute($attribute)) {
        $object->$attribute = $value;
      }
    }
    return $object;
}

private function has_attribute($attribute) {
  // We don't care about the value, we just want to know if the key exists
  // Will return true or false
  return array_key_exists($attribute, $this->attributes());
}

protected function attributes() { 
    // return an array of attribute names and their values
  $attributes = array();
  foreach(self::$db_fields as $field) {
    if(property_exists($this, $field)) {
      $attributes[$field] = $this->$field;
    }
  }
  return $attributes;
}

protected function sanitized_attributes() {
  global $database;
  $clean_attributes = array();
  // sanitize the values before submitting
  // Note: does not alter the actual value of each attribute
  foreach($this->attributes() as $key => $value){
    $clean_attributes[$key] = $database->escape_value($value);
  }
  return $clean_attributes;
}

// replaced with a custom save()
// public function save() {
//   // A new record won't have an id yet.
//   return isset($this->id) ? $this->update() : $this->create();
// }

public function create() {
    global $database;
    // Don't forget your SQL syntax and good habits:
    // - INSERT INTO table (key, key) VALUES ('value', 'value')
    // - single-quotes around all values
    // - escape all values to prevent SQL injection
    $attributes = $this->sanitized_attributes();
  $sql = "INSERT INTO ".self::$table_name." (";
    $sql .= join(", ", array_keys($attributes));
  $sql .= ") VALUES ('";
    $sql .= join("', '", array_values($attributes));
    $sql .= "')";
  if($database->query($sql)) {
    $this->id = $database->insert_id();
    return true;
  } else {
    return false;
  }
}

public function update() {
  global $database;
    // Don't forget your SQL syntax and good habits:
    // - UPDATE table SET key='value', key='value' WHERE condition
    // - single-quotes around all values
    // - escape all values to prevent SQL injection
    $attributes = $this->sanitized_attributes();
    $attribute_pairs = array();
    foreach($attributes as $key => $value) {
      $attribute_pairs[] = "{$key}='{$value}'";
    }
    $sql = "UPDATE ".self::$table_name." SET ";
    $sql .= join(", ", $attribute_pairs);
    $sql .= " WHERE id=". $database->escape_value($this->id);
  $database->query($sql);
  return ($database->affected_rows() == 1) ? true : false;
}

public function delete() {
    global $database;
    // Don't forget your SQL syntax and good habits:
    // - DELETE FROM table WHERE condition LIMIT 1
    // - escape all values to prevent SQL injection
    // - use LIMIT 1
  $sql = "DELETE FROM ".self::$table_name;
  $sql .= " WHERE id=". $database->escape_value($this->id);
  $sql .= " LIMIT 1";
  $database->query($sql);
  return ($database->affected_rows() == 1) ? true : false;

    // NB: After deleting, the instance of User still 
    // exists, even though the database entry does not.
    // This can be useful, as in:
    //   echo $user->first_name . " was deleted";
    // but, for example, we can't call $user->update() 
    // after calling $user->delete().
}

}

?>`
当我做同样的事情,但与一个对象的照片实例

$photo_object = new Photograph();
$photos = find_all();
如果我试着和他做同样的循环,我只会一次又一次地得到相同的结果(目前数据库中有4个条目,我得到了大约10次完全相同的条目)

这是我的代码,它产生了这个输出

<?php require_once("../../includes/initialize.php"); ?>
<?php if(!$session->is_logged_in()) { redirect_to("login.php");} ?>
<?php 

     //This is the class being called
    $photo_object = new Photograph();

     //Find all photos will return the result from the database. We then need to call the fetch array onit
     //$photos = $photo_object->find_all_photos();
    $photos = $photo_object->find_all();
?>


 <?php include_layout_template('admin_header.php'); ?>

<h2>Photographs: List</h2>
<?php echo output_message($message);?>
<table class="bordered">

<tr>
<th>Image</th>
<th>Filename</th>
<th>Caption</th>
<th>Size</th>
<th>Type</th>
<th>&nbsp;</th>
</tr>
  <?php foreach($photos as $photo): ?>
 <tr>
 <td><img src="<?php echo "../" . $photo_object->image_path() .     $photo_object->filename;?>" width="100" /></td>
<td><?php echo $photo_object->filename; ?></td>
 <td><?php echo $photo_object->caption; ?></td>
<td><?php echo $photo_object->size_as_text($photo_object->size); ?></td>
 <td><?php echo $photo_object->type ?></td>
<td><a href="delete_photo.php?id=<?php echo $photo_object->id;?>">Delete</a>    </td>
</tr>
 <?php endforeach; ?>

</table>
<br />
<a href="photo_upload.php">Upload a new photograph</a>

<?php include_layout_template('admin_footer.php'); ?>
这是可行的,但我不使用类中的任何变量,而是调用我在foreach循环(foreach($photos as$photo))中创建的photo数组。这使得类中的属性看起来毫无意义。我这样做对了吗?还是有什么东西我只是不了解的对象

提前谢谢你对我的帮助


快乐编码

现在的代码将
$object\u数组
传递到
实例化

但是,
instantiate
被构建为只接受从结果集检索到的一行

如果在传递它之前检查
$object\u array
,您将了解获得不希望的结果的更多原因

public function find_by_sql($sql="") {
    global $database;
    $result = $database->query($sql);
    $object_array = $database->fetch_array($result);

    // Examine $object_array:
    print '<pre>';
    var_dump($object_array);
    print '</pre>';

    $object = $this->instantiate($object_array);

    return $object_array;
}
我建议取消对它们的注释,并检查
$row

private function instantiate($record) {

    //Could check if $record exists and is an array

    //Simple long form approach
     //$object = new self;
     $this->id= $record['id'];
     $this->filename    = $record['filename'];
     $this->type    = $record['type'];
     $this->size  = $record['size'];
     $this->caption   = $record['caption'];
}
这是一个开始,让你了解为什么你会看到10倍相同的结果

我写了一个例子来说明你将如何去做你想要做的事情(从你的评论中决定):

或者当您想使用您的线路时:


您可以这样做:



我希望这能为您澄清一些问题。

您现在拥有的代码将
$object\u array
传递到
实例化中

但是,
instantiate
被构建为只接受从结果集检索到的一行

如果在传递它之前检查
$object\u array
,您将了解获得不希望的结果的更多原因

public function find_by_sql($sql="") {
    global $database;
    $result = $database->query($sql);
    $object_array = $database->fetch_array($result);

    // Examine $object_array:
    print '<pre>';
    var_dump($object_array);
    print '</pre>';

    $object = $this->instantiate($object_array);

    return $object_array;
}
我建议取消对它们的注释,并检查
$row

private function instantiate($record) {

    //Could check if $record exists and is an array

    //Simple long form approach
     //$object = new self;
     $this->id= $record['id'];
     $this->filename    = $record['filename'];
     $this->type    = $record['type'];
     $this->size  = $record['size'];
     $this->caption   = $record['caption'];
}
这是一个开始,让你了解为什么你会看到10倍相同的结果

我写了一个例子来说明你将如何去做你想要做的事情(从你的评论中决定):

或者当您想使用您的线路时:


您可以这样做:



我希望这能为您澄清一些问题。

您的函数“find_all”函数是否位于Photograph类中?当您想在像find_all()这样的对象中调用函数时,必须指定objectinstance:$photo_object->find_all();很抱歉是的,我的全部都找到了。确实住在摄影班里,我在我的帖子里犯了一个错误。我本来打算把$photos=$photo\u object->find\u all()放在上面,而不是=find\u all()。它仍然不起作用,我只是一遍又一遍地从数据库中得到相同的结果。这就好像类中的变量在循环发生时不发生变化。在我看来,这就像ActiveRecord。您没有使用这些属性,因为您正在实现和讨论静态的存储库方法。我猜在收到一个对象后,您可以修改它,然后保存它,然后执行相对SQL。这是一个ORM的原始实现。好的,很好!:)你能展示你得到的输出,并解释你想要的输出是什么,它们之间的区别是什么吗?对。我已将代码改回在photo类中使用标准的find_all()。因此,我的代码现在读取$photo_object=new photo();然后我调用这个方法,说$photos=$photo_object->find_all();然后我执行相同的foreach循环,但我回显$photo_object->variable bambol.jpg这是一些竹子的照片445 KB image/jpeg,然后我得到上面返回的10次。每个循环中给出的数据相同。函数“find_all”是否驻留在Photoshot类中?当您想在像find_all()这样的对象中调用函数时,必须指定objectinstance:$photo_object->find_all();很抱歉是的,我的全部都找到了。确实住在摄影班里,我在我的帖子里犯了一个错误。我本来打算把$photos=$photo\u object->find\u all()放在上面,而不是=find\u all()。它仍然不起作用,我只是一遍又一遍地从数据库中得到相同的结果。这就好像类中的变量在循环发生时不发生变化。在我看来,这就像ActiveRecord。您没有使用这些属性,因为您正在实现和讨论静态的存储库方法。我猜在收到一个对象后,您可以修改它,然后保存它,然后执行相对SQL。这是一个ORM的原始实现。好的,很好!:)你能展示你得到的输出,并解释你想要的输出是什么,它们之间的区别是什么吗?对。我已将代码改回在photo类中使用标准的find_all()。因此,我的代码现在读取$photo_object=new photo();然后我调用这个方法,说$photos=$photo_object->find_all();然后我执行相同的foreach循环,但我回显$photo_object->variable bambol.jpg这是一些竹子的照片445 KB image/jpeg,然后我得到上面返回的10次。每个循环中给出的相同数据非常感谢您,回答得很好。我现在明白了我的错误,现在我明白了,这似乎是很明显的。当我在写了多年程序性的东西之后开始我的OO编程之旅时,它让我忙了好几个月!我很高兴我能
public function find_all_photos() {
    global $database;
    $query = "SELECT * FROM {$this->table_name}";
    $result = $database->query($query);

    return $result;
}
public function find_by_sql($sql="") {
    global $database;
    $result = $database->query($sql);
    $object_array = $database->fetch_array($result);

    // Examine $object_array:
    print '<pre>';
    var_dump($object_array);
    print '</pre>';

    $object = $this->instantiate($object_array);

    return $object_array;
}
 //while($row = $database->fetch_array($result)) {
        //$object_array[] = $this->instantiate($row);
    //}
 while( $row = $database->fetch_array($result) ) {

    // Examine $row:
    print '<pre>';
    print_r( $row );
    print '</pre>';

        //$object_array[] = $this->instantiate($row);
 }
private function instantiate($record) {

    //Could check if $record exists and is an array

    //Simple long form approach
     //$object = new self;
     $this->id= $record['id'];
     $this->filename    = $record['filename'];
     $this->type    = $record['type'];
     $this->size  = $record['size'];
     $this->caption   = $record['caption'];
}
/**
 * A new class 'Photographs' to 'manage' the collection of photographs:
 **/
class Photographs {

    protected static $table_name="photographs";

    public $photographObjects = array();

    function __construct() {
        // The constructor runs on creation/instantiation of the 'Photographs' object

        print 'Photographs object created...';
    }

    // Retrieves the data and instantiates Photograph objects:
    public function get_photographs() {
        global $database;

        $sql = "SELECT * FROM ". $this->table_name;

        $this->photographObjects = array(); // empty the array before filling it

        $result = $database->query($sql);

        while( $row = $database->fetch_array( $result ) ) {
            $tmpPhotograph = new Photograph();
            $tmpPhotograph->id = $row['id'];
            $tmpPhotograph->filename = $row['filename'];
            // etc etc (or make the 'instantiate' function of the 'Photograph' class public, so you can do:
            // $tmpPhotograph->instantiate($row);
            // Now add a created and initialized object to your array:
            $this->photographObjects[] = $tmpPhotograph;
        }
    }


    // render the photographs:
    public function render_photographs() {

        if ( count($this->photographObjects) > 0 ) { 
            // loop through the objects in the photograpsObjects array:

            foreach ( $this->photographObjects as $tmpPhotograph ) {
                // in this line you can see that public properties (filename), and functions (image_path()) are available:
                print '<img src="../' . $tmpPhotograph->image_path() .     $tmpPhotograph->filename . '" width="100" />';

            }
        } else {
            // Nothing found, inform the user:
            print 'No photographs in array';
        }
    }



}
$photographManager = new Photographs();
$photographManager->get_photographs(); // retrieve them

$photographManager->render_photographs(); // output them
<?php foreach($photos as $photo): ?>
<?php foreach( $photographManager->photographObjects as $photo ): ?>