php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #44337 PDO::FETCH_CLASS and visibility private (private constructor, private property)
Submitted: 2008-03-05 15:29 UTC Modified: 2009-05-03 01:00 UTC
Votes:13
Avg. Score:4.1 ± 1.4
Reproduced:10 of 11 (90.9%)
Same Version:0 (0.0%)
Same OS:5 (50.0%)
From: uwendel at mysql dot com Assigned:
Status: No Feedback Package: PDO related
PHP Version: 5.2CVS-2008-03-05 (CVS) OS: *
Private report: No CVE-ID: None
Have you experienced this issue?
Rate the importance of this bug to you:

 [2008-03-05 15:29 UTC] uwendel at mysql dot com
Description:
------------
Please clearify if any of the following is a bug or a feature.

1) PDO::FETCH_CLASS and private constructor

PDO ignores the visibility "private" of a constructor and creates objects of the requested type when using PDO::FETCH_CLASS and PDOStatement->fetch().

Create a class with a private constructor and try to create an object of the class from somewhere outside of the class. PHP will print a fatal error as expected.

class private_constructor {
  private function __construct()
}
$obj = new private_constructor() --> Fatal error (OK)

Use PDOStatement->setFetchMode() to make PDO return objects of the type "private_constructor" when fetching results. setFetchMode() will return true and PDOStatement->fetch() will return objects of the type "private_constructor". In other words: PDO will ignore the visibility of the constructor and behave as if PDO would be a part of the class "private_constructor"

2) PDO::FETCH_CLASS and private properties

Something similar happens if you make PDO instantiate a class with private properties which have the same name as column in the result set. PDO does not bother about private and fills the appropriate properties with values from the result set.



Reproduce code:
---------------
---------------- 1 - private constructor -------------


php -r '$db = new PDO("sqlite:/tmp/foo"); $db->exec("DROP TABLE test"); $db->exec("CREATE TABLE test (id INT)"); $db->exec("INSERT INTO test(id) VALUES (1)"); $stmt = $db->prepare("SELECT id FROM test"); class private_constructor { public static $calls = 0; private function __construct() { printf("private_constructor: %d\n", self::$calls++); }} $stmt->setFetchMode(PDO::FETCH_CLASS, 'private_constructor'); $stmt->execute(); var_dump($stmt->fetch());'
private_constructor: 0
object(private_constructor)#3 (1) {
  ["id"]=>
  string(1) "1"
}

--------------------- 2 - private properties -------------------


php -r '$db = new PDO("sqlite:/tmp/foo"); $db->exec("DROP TABLE test"); $db->exec("CREATE TABLE test (id INT)"); $db->exec("INSERT INTO test(id) VALUES (1)"); $stmt = $db->prepare("SELECT id FROM test"); class private_properties { public static $calls = 0; private $id; public function __construct() { printf("private_properties: %d\n", self::$calls++); }} var_dump($stmt->setFetchMode(PDO::FETCH_CLASS, 'private_properties')); $stmt->execute(); var_dump($stmt->fetch());'
bool(true)
private_properties: 0
object(private_properties)#3 (1) {
  ["id":"private_properties":private]=>
  string(1) "1"
}



Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2009-04-25 14:56 UTC] jani@php.net
Why is this here? You should discuss stuff on the mailing lists, nobody 
seems to read the bug reports (who actually know the stuff..).
 [2009-05-03 01:00 UTC] php-bugs at lists dot php dot net
No feedback was provided for this bug for over a week, so it is
being suspended automatically. If you are able to provide the
information that was originally requested, please do so and change
the status of the bug back to "Open".
 [2012-08-09 18:32 UTC] Stephen dot Reay at me dot com
This bug still exists in PHP 5.3 - what extra information is required for this to 
be fixed?
 [2013-04-04 14:55 UTC] technik at thomas-heuer dot eu
This bug is still open;

$ php --version
PHP 5.3.10-1ubuntu3.6 with Suhosin-Patch (cli) (built: Mar 11 2013 14:31:48)


Complete test case follows.

test database:
-------------------------

CREATE DATABASE `test` DEFAULT CHARACTER SET utf8 COLLATE=utf8_unicode_ci;
USE `test`;

CREATE TABLE IF NOT EXISTS `test` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `value` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

INSERT INTO `test` (`id`, `value`) VALUES
(1, 'Some'),
(2, 'test'),
(3, 'entries'),
(4, 'in'),
(5, 'this'),
(6, 'database.');
-------------------------

example code:
-------------------------
$db = new PDO( 'mysql:host=localhost;port=3306;dbname=test;', 'root', 'PASSWORD', array( PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8' ) );

class IdObject
{
	private $id;
	private $value;

	public function setId( $id )
	{
		$this->id = (int) $id;
	}

	public function setValue( $value )
	{
		$this->value = $value . ' (via setter)';
	}
}

$stmt = $db->prepare( 'SELECT `id`, `value` FROM `test`;' );
$stmt->execute();
$stmt->setFetchMode( PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, 'IdObject' );
$objects = array();
while( $row = $stmt->fetch() )
{
	$objects[] = $row;
}
var_dump( $objects );
-------------------------

example output:
-------------------------
object(IdObject)#3 (2) {
	["id":"IdObject":private]=>
	string(1) "1"
	["value":"IdObject":private]=>
	string(4) "Some"
}
-------------------------

As you can see, the private members were set without using the setter as expected. Even if you set up a magic method `__set()` it won't get used.

The same is true when using private constructors (objects are still initialized) or protected members or constructors.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Apr 19 19:01:28 2024 UTC