0

私はPDOで非常に奇妙な振る舞いをしています。時間がかかりすぎるため、詳細については説明しませんが、基本的に、単純なINSERTを実行する\ PDOStatementを再利用すると、PDO :: lastInsertId( )。

ステートメントを初めて実行すると、正常に機能し、正しいIDが返されます。後続の実行では、代わりに常に「0」が返されます。これはテスト間(PHPUnitのもの)でのみ発生するため、さらに奇妙です。つまり、test1(動作中)でpreparedステートメントを使用して挿入を実行すると、test2では惨めに失敗します。

単体テスト以外の環境(インスタンスの単純なphpファイル)でプリペアドステートメントを複数回実行すると、すべて正常に機能し、最後に挿入されたIDは常に正確です。確かに非常に奇妙です。

テストは次のとおりです(PersistencyManagerInstanceはPersistencyManagerの単なるインスタンスであることに注意してください)。

<?php

class PersistencyManagerTest extends PHPUnit_Framework_TestCase {

   const DELETE_ALL = "TRUNCATE user";
   const ADD_USER = "INSERT INTO user values(null, :username, :password)";
   const CHECK_USER_EXISTENCE = "SELECT * FROM user WHERE username = :username AND password = :password";
   const DELETE_USER_BY_ID = "DELETE FROM user WHERE id = ?";

   protected $manager = null;

   public function __construct() {
      $this->manager = new PersistencyManagerInstance(PDOFactory::build());
   }

   public function setUp() {
      $this->manager->exec(self::DELETE_ALL);
   }

   public function tearDown() {
      $this->manager->exec(self::DELETE_ALL);
   }

   public function testInsert() {
      $user = new User("laurent", "password");
      $id = $this->manager->insert(self::ADD_USER, $user->export());
      $this->assertEquals("1", $id);
   }

   public function testInsertAgain() {
      $user1 = new User("laurent1", "password1");
      $id = $this->manager->insert(self::ADD_USER, $user1->export());
      $this->assertEquals("1", $id);
   }

   public function testQuery() {
      $user = new User("laurent", "password");
      $this->manager->insert(self::ADD_USER, $user->export());
      $results = $this->manager->query(self::CHECK_USER_EXISTENCE, $user->export());
      $this->assertEquals(1, count($results));
   }

   public function testExec() {
      $user = new User("laurent", "password---");
      $id = $this->manager->insert(self::ADD_USER, $user->export());
      $affected = $this->manager->exec(self::DELETE_USER_BY_ID, array($id));
      $this->assertEquals(1, $affected);
   }
}

testInsertは機能しますが、testInsertAgainは機能しません。

そしてここにクラスがあります:

<?php

namespace memory\manager;

use \PDO;

abstract class PersistencyManager {

   /**
    * @var array An array of \PDOStatement objects
    */
   protected static $ps = array();

   /**
    * @var \PDO 
    */
   protected $connection = null;

   protected function prepareStmt($sql) {
      // return $this->connection->prepare($sql);
      $key = md5($sql);
      if (!isset(self::$ps[$key])) {
         self::$ps[$key] = $this->connection->prepare($sql);
      }
      return self::$ps[$key];
   }

   public function __construct(PDO $connection) {
      $this->connection = $connection;
      $this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
   }

   public function __destruct() {
      $this->connection = null;
   }

   /**
    * Good for SELECT operations. By default it fetches using arrays.
    * @param string $sql
    * @param array $values
    * @param integer $fetchStyle
    * @return array A list of matching elements (The elements' type depends on $fetchStyle)
    */
   public function query($sql, array $values = array(), $fetchStyle = PDO::FETCH_ASSOC) {
      $prepared = $this->prepareStmt($sql);
      $prepared->execute($values);
      $prepared->setFetchMode($fetchStyle);
      $all = $prepared->fetchAll();
      $prepared->closeCursor();
      return $all;
   }

   /**
    * Good for INSERT operations.
    * @param string $sql
    * @param array $values
    * @return string Last inserted element's id in string format
    */
   public function insert($sql, array $values = array()) {
      $prepared = $this->prepareStmt($sql);
      $prepared->execute($values);
      $prepared->closeCursor();
      return $this->connection->lastInsertId();
   }

   /**
    * Good for all the remaining routines.
    * @param string $sql
    * @param array $values
    * @return integer The number of effected rows
    */
   public function exec($sql, array $values = array()) {
      $prepared = $this->prepareStmt($sql);
      $prepared->execute($values);
      $count = $prepared->rowCount();
      $prepared->closeCursor();
      return $count;
   }
}

何か案が?

乾杯

4

1 に答える 1

0

みんな私はすべてのテストで新しい接続を開始していました。それが理由でした。

于 2012-12-02T15:12:27.113 に答える