php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #55701 GlobIterator throws LogicException
Submitted: 2011-09-15 13:42 UTC Modified: 2016-07-05 15:13 UTC
Votes:33
Avg. Score:4.2 ± 0.9
Reproduced:32 of 32 (100.0%)
Same Version:11 (34.4%)
Same OS:20 (62.5%)
From: bs@php.net Assigned: cmb (profile)
Status: Closed Package: SPL related
PHP Version: 5.3.8 OS: Linux, OSX
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: bs@php.net
New email:
PHP Version: OS:

 

 [2011-09-15 13:42 UTC] bs@php.net
Description:
------------
Basic functionality doesn't work because it seems as the GlobIterator might needs 
some changes to work with this commit: 
http://marc.info/?l=php-cvs&m=130188548616717

Test script:
---------------
<?php
$g = new \GlobIterator(__DIR__ . '/*');

do {
    $g->next();
} while($g->valid());

Expected result:
----------------
Empty output

Actual result:
--------------
PHP Fatal error:  Uncaught exception 'LogicException' with message 'The parent 
constructor 
was not called: the object is in an invalid state ' in /private/tmp/x.php:6
Stack trace:
#0 /private/tmp/x.php(6): SplFileInfo->_bad_state_ex()
#1 {main}
  thrown in /private/tmp/x.php on line 6

Fatal error: Uncaught exception 'LogicException' with message 'The parent 
constructor was not 
called: the object is in an invalid state ' in /private/tmp/x.php:6
Stack trace:
#0 /private/tmp/x.php(6): SplFileInfo->_bad_state_ex()
#1 {main}
  thrown in /private/tmp/x.php on line 6

Patches

Add a Patch

Pull Requests

Pull requests:

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2011-09-16 00:21 UTC] felipe@php.net
-Status: Open +Status: Assigned -Assigned To: +Assigned To: cataphract
 [2012-03-19 21:24 UTC] maciej dot sz at gmail dot com
Not sure if this is the same issue, but I've experienced something very similar 
when extending SplFileObject (see Script 1 below). This might seem to be of very 
little importance, as no one would ever want to extend this class in that way. 
But with the introduction of traits this became a real problem, becouse using 
trait methods that share the same name with a SplFileObject method causes to 
throw the mentioned LogicException. This happens when the method is used in 
constructor prior to calling the parent constructor even if the trait method is 
aliased (see Script 2 below).


Script 1:
--------------
<?php

class MyFileObject extends \SplFileObject
{
    public function __construct($fname)
    {
        /**
         * This throws LogicException despite of that we have
	 * overloaded the getRealPath method making it independent
	 * of the object state.
         */
        $new_fname = $this->getRealPath();

        parent::__construct($fname);
    }

    public function getRealPath()
    {
        return '/tmp/foo.txt';
    }
}

$f1 = new MyFileObject(__FILE__);




Script 2
--------------
<?php

trait NewFileTrait
{
    public function getRealPath()
    {
        return __FILE__ . '.new';
    }
}

class MyFileObject extends \SplFileObject
{
    use NewFileTrait {

        /**
         * The method getRealPath is defined in SplFileObject,
         * so we'll use alias:
         */
        NewFileTrait::getRealPath as newFileGetRealPath;
    }

    public function __construct($fname)
    {
        /**
         * This throws LogicException despite using aliased method.
         * This should not be happening, as we are not using any
         * methods of the SplFileObject class, just the aliased method
         * of our trait which happens to share the same name with
         * a SplFileObject method.
         */
        $new_fname = $this->newFileGetRealPath();

        parent::__construct($new_fname);
    }
}

$f1 = new MyFileObject(__FILE__);
 [2012-12-21 12:18 UTC] ivanderberg at hostnet dot nl
I can confirm what "[2012-03-19 21:24 UTC] maciej dot sz at gmail dot com" said 
in a more simplistic way. This class fails in my current version (PHP 5.3.14 
(cli) (built: Jun 19 2012 07:35:36)) on $this->touchLockFile(...)

As I really need $file before calling the parent constructor, I have no other 
option than making it static

<?php
/**
 * @author Iltar van der Berg <ivanderberg@hostnet.nl>
 */
class Lock extends \SplFileObject
{
  /**
   * @param string     $file_name
   * @param string     $open_mode
   * @param Filesystem $filesystem
   * @param string     $lock_directory
   */
  public function __construct($file_name, $open_mode = 'r', Filesystem 
$filesystem = null, $lock_directory = '/var/lock')
  {
    $filesystem = $filesystem ?: new Filesystem();
    $file = $this->touchLockFile($file_name, $lock_directory, $filesystem);
    parent::__construct($file, $open_mode);
  }

  /**
   * Returns true if the lock is placed, false if unable to
   *
   * @return boolean
   */
  public function lock()
  {
    return $this->flock(LOCK_EX | LOCK_NB);
  }

  /**
   * Returns true if the lock is released
   *
   * @return bool
   */
  public function release()
  {
    return $this->flock(LOCK_UN);
  }

  /**
   * Attempts to create a lock file for a given filename and directory
   * it will return a string if the file is touched
   *
   * @param  string     $file_name
   * @param  string     $lock_directory
   * @param  Filesystem $filesystem
   * @return string
   */
  private function touchLockFile($file_name, $lock_directory, Filesystem 
$filesystem)
  {
    $lock_file_path = explode('/', $file_name);
    $lock_file      = array_pop($path);

    $path = empty($lock_file_path)
      ? "$lock_directory/$lock_file"
      :  $lock_directory . implode('/', $lock_file_path);

    $lock_file = "$path/$lock_file.lock";

    if(!$filesystem->exists($path) || !is_dir($path)) {
      $filesystem->mkdir($path, 0733);
    }

    // some modes create this file already, but we force it in
    // that way the lock file always exists no matter what mode
    $filesystem->touch($lock_file);
    return $lock_file;
  }
}
?>
 [2013-01-28 07:38 UTC] sergei dot solomonov at gmail dot com
I have same problem too.
OS: windows 7 x64, PHP 5.4.7 (built: Sep 12 2012 23:48:31).
I working with ZF2, when I trying to use phar-packed modules same error occured.
But in Ubuntu works fine.
 [2013-08-02 11:54 UTC] rosier at interstroom dot nl
I can confirm this unexpected result also for php54 and php55

Test script:
---------------
<?php

$path_to_files = sys_get_temp_dir();

// Next works as expected: no xml files found = no output
foreach (new GlobIterator($path_to_files . '/*.xml') as $fileinfo) {
    echo $fileinfo->getFilename() . "\n";
}

$it = new GlobIterator($path_to_files . '/*.xml');
// Expected result: count = 0
// Instead next line will crash php if no xml files are found
if ($it->count()) {
    // do something...
}

?>
 [2014-02-26 14:11 UTC] log dot kot at gmail dot com
Confirm the bug

Ubuntu Linux 13.10 3.11.0-17-generic x86_64

PHP 5.5.3-1ubuntu2.1 (cli) (built: Dec 12 2013 04:24:35) 
Copyright (c) 1997-2013 The PHP Group
Zend Engine v2.5.0, Copyright (c) 1998-2013 Zend Technologies
    with Zend OPcache v7.0.3-dev, Copyright (c) 1999-2013, by Zend Technologies
    with Xdebug v2.2.3, Copyright (c) 2002-2013, by Derick Rethans
 [2014-08-10 10:53 UTC] hanskrentel at yahoo dot de
SplFileObject checks on method invocation that the state is sane - it does not care whether or not you have it extended.

Whether or not this qualifies as a bug (I tend to say it isn't a flaw, because SplFileObject has it's responsibilities and if you extend from it, you're explicitly stating that your object comes with the same responsibilities, you can not lower the checks).

However, if you actually want to stub the file-object first, that must not stand in your way, it's easy to work-around, for example with a fake "data://" URI:

<?php
/*
 * File: test.php
 * Link: https://bugs.php.net/bug.php?id=55701
 */

class MyFileObject extends \SplFileObject
{
    public function __construct($file_name)
    {
        parent::__construct("data://,");

        $new_fname = $this->getRealPath();

        parent::__construct($file_name);
    }

    public function getRealPath()
    {
        return '/tmp/foo.txt';
    }
}

$f1 = new MyFileObject(__FILE__);

var_dump($f1->getBasename()); # string(8) "test.php"
 [2014-08-10 10:57 UTC] hanskrentel at yahoo dot de
Additionally I can not reproduce the original report:

-----------------------------------------------------
<?php

$g = new \GlobIterator(__DIR__ . '/*');

do {
    $g->next();
} while($g->valid());

----------------------------------------------------

Works flawlessly for me. Using 5.5.15
 [2016-01-11 16:24 UTC] pheagey at gmail dot com
Able to reproduce error in 5.5.6 on Ubuuntu 14.04

$iterator = new GlobIterator('./someDir/*');
$iterator->count();

Where 'someDir' has not contents.
 [2016-02-08 10:30 UTC] axiac dot ro at gmail dot com
Tested on PHP 5.3, 5.4, 5.5, 5.6 and 7.0 on OSX and Ubuntu. It fails the same on all of them.


<?php
error_reporting(E_ALL);
ini_set('display_errors', '1');

$g = new \GlobIterator('/tmp/*.txt');
echo('Before: '.$g->count()."\n");
foreach ($g as $f) {
}
echo('After : '.$g->count()."\n");


If the glob expression matches at least one file it throws the exception on the second call to count() (line 9). If it doesn't match then it throws on the first call to count() (line 6).

Not only count() throws the exception. All its methods do the same.
 [2016-07-05 13:49 UTC] cmb@php.net
-Assigned To: cataphract +Assigned To: cmb
 [2016-07-05 13:49 UTC] cmb@php.net
I can confirm this behavior with current master.

> This happens when the method is used in constructor prior to
> calling the parent constructor even if the trait method is
> aliased […]

As hanskrentel already explained, this doesn't appear to be a bug.
Anyhow, it's not related to this very issue, so feel free to file
another ticket.
 [2016-07-05 14:41 UTC] cmb@php.net
-Summary: GlobIterator throws LogicException with message 'The parent constructor was not +Summary: GlobIterator throws LogicException
 [2016-07-05 14:57 UTC] cmb@php.net
Automatic comment on behalf of axiac.ro@gmail.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=4c24f170ea3701c9aadde6c575a777ee4027f463
Log: Fix bug #55701: GlobIterator throws LogicException
 [2016-07-05 14:57 UTC] cmb@php.net
-Status: Assigned +Status: Closed
 [2016-07-05 14:59 UTC] cmb@php.net
Automatic comment on behalf of axiac.ro@gmail.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=4c24f170ea3701c9aadde6c575a777ee4027f463
Log: Fix bug #55701: GlobIterator throws LogicException
 [2016-07-06 05:47 UTC] davey@php.net
Automatic comment on behalf of axiac.ro@gmail.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=4c24f170ea3701c9aadde6c575a777ee4027f463
Log: Fix bug #55701: GlobIterator throws LogicException
 
PHP Copyright © 2001-2017 The PHP Group
All rights reserved.
Last updated: Sun Nov 19 01:31:42 2017 UTC