ID:               31525
 User updated by:  yml at yml dot com
 Reported By:      yml at yml dot com
-Status:           Feedback
+Status:           Open
 Bug Type:         Zend Engine 2 problem
 Operating System: Linux (redhat 9)
 PHP Version:      5.0.3
 New Comment:

Here's the complete test script I put together. The errors are
commented in the code. 

<?php

// -----------------------------------------------------------------
// Copyright (C) DTLink, LLC., All Rights Reserved.
//
// Unless explicitly acquired and licensed from Licensor under the
// DTLink Commercial Software License ("DCL") Version 1.0 or greater,
the
// contents of this file are subject to the Reciprocal Public License
// ("RPL") Version 1.1, or subsequent versions as allowed by the RPL,
// and You may not copy or use this file in either source code or
// executable form, except in compliance with the terms and conditions
// of the RPL.
// 
// You may obtain a copy of both the DCL and the RPL (the "Licenses")
// from DTLink, LLC. at http://www.formvista.com.
// 
// All software distributed under the Licenses is provided strictly on
// an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR
// IMPLIED, AND TECHNICAL PURSUIT INC. HEREBY DISCLAIMS ALL SUCH
// WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT,
// OR NON-INFRINGEMENT. See the Licenses for specific language
// governing rights and limitations under the Licenses.
// ------------------------------------------------------------------

class fvTree
        {

        var $root;                      // the root node of the tree.
        var $parent;            // parent node.
        var $children;          // array of child nodes.
        var $nChildren; // number of children
        var $curChild;          // child to be called on getNextChild() call.
        var $depth;                     // depth of this child in the tree.
                
        // constructor
        
        function fvTree( &$root, &$parent )
                {

                $this->children = array();
                $this->root = &$root;
                $this->parent = &$parent;
        
                $this->nChildren = 0;
                $this->curChild = 0;

                if ( $parent != NULL )
                        $this->depth = $parent->depth + 1;
                else
                        $this->depth = 0;
                                                        
                }
                
        // adds a child node onto the end of the children list.
        
        function addChild( &$childNode )
                {
                
                $this->children[ count( $this->children ) ] =& $childNode;
                $this->nChildren++;                             
                
                // set the depth of the child.
                
                $childNode->depth = $this->depth + 1;

                $childNode->setParent( $this );
                
                }

        // returns first child node
        
        function &getFirstChild()
                {

                if ( $this->nChildren == 0 )
                        {
                        return( NULL );
                        }

                $this->curChild = 1;
                
                return( $this->children[ 0 ] );
                
                }

        // returns NULL if we've reached the end of the list
        
        function &getNextChild()
                {
                
                if ( $this->nChildren == 0 )
                        {
                        return( NULL );
                        }
                        
                $this->curChild++;

                if ( $this->curChild > $this->nChildren )
                        {
                        return( NULL );
                        }

                // our number of children counts start at 1 while the
                // array offsets start at 0.
                                                        
                return( $this->children[ $this->curChild - 1 ] );
                
                }               

        // ---------------------------------------------------------
        // return reference of children array

        function &getChildren()
                {
                return( $this->children );
                }

        // ---------------------------------------------------------
        // Used for nested looping
        //
        // Ideally I would have liked to put a default value on a reference
        // parameter so we could just have used the functions above .. but
PHP
        // does not seem to support such a syntax.

        // returns first child node
        
        function &getFirstChildIterator( &$iterator )
                {

                if ( $this->nChildren == 0 )
                        {
                        return( NULL );
                        }

                $iterator = 1;
                
                return( $this->children[ 0 ] );
                
                }

        // returns NULL if we've reached the end of the list
        
        function &getNextChildIterator( &$iterator )
                {
                
                if ( $this->nChildren == 0 )
                        {
                        return( NULL );
                        }
                        
                $iterator++;

                if ( $iterator > $this->nChildren )
                        {
                        return( NULL );
                        }

                // our number of children counts start at 1 while the
                // array offsets start at 0.
                                                        
                return( $this->children[ $iterator - 1 ] );
                
                }               
                 
        // returns the deepest point in the tree as an integer.
                        
        function getMaxDepth( $prevDepth )
                {

                $currentDepth = $prevDepth + 1;
                $maxDepth = $currentDepth;
                
                $child = &$this->getFirstChild();
                
                while ( $child != NULL )
                        {
                                                                                
 
                        $depth = $child->getMaxDepth( $currentDepth );
                        
                        if ( $depth > $maxDepth )
                                $maxDepth = $depth;
                                
                        $child = &$this->getNextChild();
                        
                        }               

                return( $maxDepth );
                
                }       // end of getMaxDepth()

        // number of children
        
        function getNumChildren()
                {
                return( $this->nChildren );
                }

        function setParent( &$parent )
                {
                $this->parent =& $parent;
                }
                
        function &getParent()
                {
                return( $this->parent );
                }
                
        function &getRoot()
                {
                return( $this->root );
                }

        function getDepth()
                {
                return( $this->depth );
                }

        // this is based on the assumption that the root of the tree is passed
NULL
        // as it's root value on creation.

        function isRoot()                                                       
                        
                {

                if ( $this->root == NULL )
                        {
                        return( true );
                        }

                return( false );

                }

        }       // end of class fvTree

//
-----------------------------------------------------------------------
// Common base class for all formvista widgets and controls.

class fv_baseWidget extends fvTree
        {

        /**
        * a reference to the tag processor. 
        */
        
        var $processor;

        /**
        * the current tag       
        */

        var $tag;

        /**
        * value of any name= attribute. name of component/tag
        */

        var $name;

        /**
        * reference to our parent control which may be several levels above us
in the widget tree.
        */
                
        var $parentControl;
        
        // ------------------------------------------------------------------

        /**
        * Constructor 
        */
                                                                                
                
        function fv_baseWidget( &$processor, &$parentControl, &$parent, $tag,
$attrs )
                {

                $this->fvTree( $parentControl, $parent );

                $this->parentControl =& $parentControl;
                $this->processor =& $processor;

                $this->tag = $tag;                      

                $this->attributes = array();

                }       // end of constructor.

        // ---------------------------------------------
        // Accessors
        
        // set name for this widget.

        function setName( $name )
                {
                $this->name = $name;
                }

        // returns an evaluated attribute

        function getAttributeValue( $name )
                {

                // ############ PHP 5 BUG ####################
                //
                // if I comment out the varLookupATTRS() call the $this 
reference in
the
                // the constructor is unaffected. It goes invalid if 
varLookupATTRS
is called.
                //
                // getParentControl is overriden in fv_baseComponent to return a
reference to
                // $this, which is where I believe the problem to be.

                $parentComponent =& $this->getParentControl();

                ddt( "fv_basewidget::getAttributeValue() - $parentComponent is 
'" .
gettype( $parentComponent ) . "'" );

                // This seems to be the method call that breaks everything in 
PHP 5.


                $value = $parentComponent->varLookupATTRS( $name, $this );

                ddt( "fv_baseWidget::getAttributeValue() - value '$value' - 
type of
parentComponent object is '" . gettype( $parentComponent ) . "'" );

                return( $value );
                }

        // ------------------------------------------------------------
        // returns a reference to the control that manages this object.
        //
        // see fv_baseComponent getParentControl() method.
        
        function &getParentControl()
                {
                return( $this->parentControl );
                }

        }       // end of fv_baseWidget

//
-----------------------------------------------------------------------

/**
* Component Base Class.
*
* This class implements the base of all formVista components. To create
a new 
* component simply subclass this class and override methods.
*/

class fv_baseComponent extends fv_baseWidget
        {

        // ------------------------------------------------------------------
        // members used only in components.
        //
        // when used in a component, contains the type of the component,
        // NULL otherwise. It's used to determine in what order we should
        // look for templates when rendering tags.
        //
        // FIXME: we may eventually need a component specific base class.
        
        var $componentType;

        // flag indicating whether or not we're a component (either true or
false)

        var $isComponent;

        /**
        * command to process and parameters.
        *
        * (Typically used in forms to handle new, edit, search, insert,
update
        * etc. commands. Basically it contains a copy of formvars sent to 
        * this component ... but can also be set into this component by
        * other components)
        */
        
        var $cmdVars;

        // parameters passed into a component (only used at component level)
        
        var $parms;
                
        // used to lookup variable name spaces more efficiently
        
        var $varLookupMap;

        var $nameSpaces;

        // ------------------------------------------------------------------
                                                                                
        
        function fv_baseComponent( &$processor, &$parentControl, &$parent,
$tag, $attrs )
                {

                $this->fv_baseWidget( $processor, $parentControl, $parent, $tag,
$attrs );

                $this->varLookupMap = array();
                $this->varLookupMap[ "ATTRS" ] = "varLookupATTRS";

                // ###########################################################
                // PHP 5 BUG IS HERE:
                //
                // if this is uncommented, the following line will generate a
                // Attempt to assign property of non-object

                ddt( "fv_baseComponent Constructor: Before getAttributeValue() 
call.
Type of 'this' is '" . gettype( $this ) . "'" );

                $value = $this->getAttributeValue( "defaultlook" );

                ddt( "fv_baseComponent Constructor: after getAttributeValue() 
call.
Type of 'this' is '" . gettype( $this ) . "'" );

                // $this reference is dropped. At the very least $this should
                // not get overwritten.

                $this->nameSpaces = array();

                // ###########################################################

                }       // end of constructor Constructor.

        /**
        * lookup attributes for this tag
        *
        * Note that evaluating the string here is done in the space of the
calling widget
        * not the compnent here. (was a nasty bug)
        *
        * In the case of a CDATA tag the attributes of the parent are
returned.
        *
        * @see fv_cdataWidget
        */

        function varLookupATTRS( $var, &$widget )
                {

                $value = "Hello from varLookupATTRS";

                return( $value );
                }

        // returns a reference to the control that manages this object.
        //
        // If we are a component, return ourselves.
        
        function &getParentControl()
                {
                return( $this );
                }

        }       // end of fv_baseComponent

// END

// debug message function.

function ddt( $msg )
{
print( "<p>" . basename( __FILE__ ) . ":" . __LINE__ . " -
<b>$msg</b>\n" );
}

// ----------------------------------------------------

$nullVar = NULL;

// ----------------------------------------------------

for ( $i=1;$i<1000;$i++ )
        {

        ddt( "Creating fv_baseComponent instance" );

        $currentComponent       =& new fv_baseComponent( $nullVar, $nullVar,
$nullVar, "static", $nullVar );

        ddt( "After creating fv_baseComponent - currentComponent type is '" .
gettype( $currentComponent ) . "'");

        $currentComponent->getAttributeValue( "hello" );

        // at this point $this is destroyed. Is "unknown type".

        ddt( "after getAttributeValue() call - currentComponent type is '" .
gettype( $currentComponent ) . "'" );

        // this method call will fail.

        $currentComponent->setName( "test" );

        ddt( "The end - currentComponent type is '" . gettype(
$currentComponent ) . "'");
        }

print( "<hr><p>the end</p>" );

?>


Previous Comments:
------------------------------------------------------------------------

[2005-01-26 09:08:22] [EMAIL PROTECTED]

Just a simple page with the script please, or paste it here.

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

[2005-01-26 05:17:23] yml at yml dot com

Umm. Check the script I put together for you at:

http://www.yml.com/homepage.html?COMP=clog_list&cmd=detail&cs_clog_entries_ref=149

If you have trouble accessing it please let me know.

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

[2005-01-26 04:32:00] [EMAIL PROTECTED]

Thank you for this bug report. To properly diagnose the problem, we
need a short but complete example script to be able to reproduce
this bug ourselves. 

A proper reproducing script starts with <?php and ends with ?>,
is max. 10-20 lines long and does not require any external 
resources such as databases, etc.

If possible, make the script source available online and provide
an URL to it here. Try to avoid embedding huge scripts into the report.



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

[2005-01-13 00:49:01] yml at yml dot com

Description:
------------
PHP 5.0.3 using the recommended php.ini with all warnings and errors
turned on. RedHat 9. Apache 1.3.33. Config:

./configure  --with-apxs=/usr/local/apache/bin/apxs
--with-mysql=/usr/local/mysql --prefix=/usr/local/php_5.0.3
--with-mcrypt=/usr/local/lib --with-gd --with-jpeg-dir=/usr/lib
--with-zlib-dir=/usr/lib --with-png-dir=/usr/lib --enable-debug
--enable-dmalloc --disable-inline-optimization

This may be related to bug http://bugs.php.net/31508. Under PHP 4.3.10
the section of code in question causes a busy loop. Under PHP 5 it
causes an object to be dropped. 

More info, sample code and a sample run can be found at:

http://www.yml.com/homepage.html?COMP=clog_list&cmd=detail&cs_clog_entries_ref=149

I have a test case that is a radically reduced version of a large body
of code. fv_baseComponent extends fv_baseWidget which extends fvTree. I
create a minimal fv_baseComponent. 

It calls a method in the fv_baseWidget base class called
getAttributeValue(). 

getAttributeValue calls getParentControl() which is present in both
fv_baseWidget and fv_baseComponent. 

In fv_baseComponent getParentControl just returns "$this".

The returned value is then used to call a method in the
fv_baseComponent class.

All this happens in the constructor for fv_baseComponent (which I
suspect is the cause of the problem).

Once the getAttributeValue() is called in the fv_baseComponent
constructor, '$this' is no longer a valid object. 

If I turn on PHP 4 compatibility mode it seems to work. The code works
under PHP 4. (however in the full application the same code seems to
have problems under PHP 4.3.10 causing a busy loop).

If you need to contact me from an email address other than [EMAIL PROTECTED]
please use the form at

http://www.yml.com/Contact_Yermo.html 

otherwise I will miss your email in all the spam I get.


Reproduce code:
---------------
See the download available at:

http://www.yml.com/homepage.html?COMP=clog_list&cmd=detail&cs_clog_entries_ref=149

It contains base_widget.php, base_component.php, fvTree.php and
test.php.

The relevant snippet from test.php contains:

$currentComponent =& new fv_baseComponent( $nullVar, $nullVar,
$nullVar, "static", $nullVar );

ddt( "After creating fv_baseComponent - currentComponent type is '" .
gettype( $currentComponent ) . "'");

$currentComponent->getAttributeValue( "hello" );

// at this point $this is destroyed. Is "unknown type".

ddt( "after getAttributeValue() call - currentComponent type is '" .
gettype( $currentComponent ) . "'" );


// this method call will fail.

$currentComponent->setName( "test" );

ddt( "The end - currentComponent type is '" . gettype(
$currentComponent ) . "'");


Expected result:
----------------
PHP should not produce any errors when the above is run.

Actual result:
--------------
test.php:30 - before class includes

test.php:30 - Creating fv_staticCtrl instance

test.php:30 - fv_baseComponent Constructor: Before getAttributeValue()
call. Type of 'this' is 'object'

test.php:30 - fv_basewidget::getAttributeValue() - Object id #1 is
'object'

test.php:30 - fv_baseWidget::getAttributeValue() - value 'Hello from
varLookupATTRS' - type of parentComponent object is 'object'

test.php:30 - fv_baseComponent Constructor: after getAttributeValue()
call. Type of 'this' is 'object'
Warning: Attempt to assign property of non-object in
/usr/local2/WWW/mobie.yml.com/mobie/admin_ui/tests/php_5_test/base_component.php
on line 125

test.php:30 - After creating fv_baseComponent - currentComponent type
is 'object'

test.php:30 - fv_basewidget::getAttributeValue() - Object id #1 is
'object'

test.php:30 - fv_baseWidget::getAttributeValue() - value 'Hello from
varLookupATTRS' - type of parentComponent object is 'object'

test.php:30 - after getAttributeValue() call - currentComponent type is
'unknown type'
Fatal error: Call to a member function setName() on a non-object in
/usr/local2/WWW/mobie.yml.com/mobie/admin_ui/tests/php_5_test/test.php
on line 59


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


-- 
Edit this bug report at http://bugs.php.net/?id=31525&edit=1

Reply via email to