0

I'm writing a function, as a learning excercise, to combine and minify css files and php files that output generated css.

Everything is fine looping through the css files but as soon it tries to push the string returned from the output buffer from the php file the array becomes an int. var_dump() yields this:

int(5)

I've also tried concatenating the strings; it works fine again until it get's to the php file, then everything previous in the string becomes 4. Like so:

4/*
* Home: Appointment Grid
*/
.difAppointmentGrid {
    margin: 2rem 0;
    font-family: "Lato" !important;
    box-shadow: -4px 4px 16px 4px hsla( 240, 0%, 0%, 0.1 );
}
. . . 

This is an example of what I'm doing in the styles.php file:

. . . 
.difAppointmentGrid header div h3 {
    margin: 0;
    padding: 1.5rem 0;
    font-size: 2rem;
    text-align: center;
    color: white;
}
<?php
for ( $h3 = 1, $o = 0.40; $h3 <= 4; ++$h3, $o += 0.20 )
{
    $rule = '.difAppointmentGrid header div:nth-child('.$h3.') h3 {'."\n\t".
            'background-color: hsla( 223, 63%, 22%, '.$o.' );'."\n".
            '}'."\n";
    echo $rule;
}
?>
.dif_grid {
    display: flex;
}
. . . 

This is the function:

function styles_init()
{
    $path = __DIR__ . '/aggregate.min.css';
    if ( is_writable( $path ) )
    {
        $r = array();
        foreach( array_filter( glob( __DIR__ . '/modules/*.*' ), 'is_file' ) as $file )
        {
            $fn = pathinfo( $file );
            if ( $fn['extension'] == 'php' || $fn['extension'] == 'css'  )
            {
                ob_start();
                include( $file );
                $x = ob_get_flush();
                $r[] = $x;
            }
        }
        $c = implode( "\n\n", $r );
        //$c = str_replace( array( ' {', ': ', ', ' ), array( '{', ':', ',' ) , str_replace( array( "\r\n", "\r", "\n", "\t", '  ', '    ', '    ' ), '', preg_replace( '!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $c ) ) );

        $f = fopen( $path, 'wb' );
        fwrite( $f, $c );
        fclose( $f );
    }
}

The weirdest part is no errors are actually thrown when array_pushing/concatenating. I don't even know exactly what question to ask because I can't actually figure out what's going wrong. I've also messed around with headers, character encoding, different ob functions, and casting ob_get_flush to string out of desperation.

Solution:

function get_include_output($file)
{
    ob_start();
    include( $file );
    return ob_get_flush();
}
function styles_init()
{
    $path = __DIR__ . '/aggregate.min.css';
    if ( is_writable( $path ) )
    {
        $r = array();
        foreach( array_filter( glob( __DIR__ . '/modules/*.*' ), 'is_file' ) as $file )
        {
            $fn = pathinfo( $file );
            if ( $fn['extension'] == 'php' || $fn['extension'] == 'css'  )
            {
                $r[] = get_include_contents( $file );
            }
        }
        $c = implode( "\n\n", $r );
        //$c = str_replace( array( ' {', ': ', ', ' ), array( '{', ':', ',' ) , str_replace( array( "\r\n", "\r", "\n", "\t", '  ', '    ', '    ' ), '', preg_replace( '!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $c ) ) );

        $f = fopen( $path, 'wb' );
        fwrite( $f, $c );
        fclose( $f );
    }
}
9
  • Where are you dumping? Also $r[] = $x is better than using array_push() here. Commented Aug 11, 2017 at 19:54
  • @GentlemanMax I just tried it with $r[ count( $r ) ] = $x; and it resulted in the same behavior. I've just been using var_dump() and error_log() to get the values as it loops. My suspicion is that this is stemming from some aspect of output buffering that I am unaware of. Commented Aug 11, 2017 at 19:59
  • 1
    You don't need the count($r) bit, regardless, you're doing var_dump($r) right after array_push()? Have you tried with ob_get_clean()? Commented Aug 11, 2017 at 20:01
  • array_push is really supposed to return new number of elements in the array Commented Aug 11, 2017 at 20:22
  • @GentlemanMax Yes, regarding both. I actually wrote the function with with ob_get_clean(), however I switched it to ob_get_flush() as the later worked more reliably, i.e., ob_get_clean() would only return the contents of style.php, ignoring any *.css files; whereas ob_get_flush() returns the contents of both file types. Commented Aug 11, 2017 at 20:35

1 Answer 1

1

I suspect the PHP file you're including is using the variable $r, so it's overwriting your variable with a number. You can avoid variable conflicts by wrapping the code that gets the result of including the file as a string in a function, since this will have its own variable scope.

function get_include_output($file) {
    ob_start();
    include($file);
    return ob_get_flush();
}

Then change your code to:

       if ( $fn['extension'] == 'php' || $fn['extension'] == 'css'  )
        {
            $x = get_include_contents($file);
            array_push( $r, $x );
        }
Sign up to request clarification or add additional context in comments.

3 Comments

This seems likely; I didn't realize that php doesn't have block level scoping. I'll have to verify this when I'm back in the office on monday. If this is the cause then that implies output buffering does not provide scope encapsulation. Is that correct?
Remember that one of the common uses of include files is to set variables. If the include file were in its own scope, it couldn't do that.
I've only just started learning PHP, so this is all really useful information. Thanks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.