Jump to content

[SOLVED] A question for PHP pros (variable as instanceof argument)


Gadgetto
 Share

Recommended Posts

Could somebody please tell me why this works ...

$templates = $this->wire('templates');
$messageTemplates = array();
$className = 'FieldtypeMessageMeta';

foreach ($templates as $t) {
    foreach ($t->fields as $f) {
        if ($f->type instanceof $className) {
            $messageTemplates[] = $t->name;
            break;
        }
    }
}
// $messageTemplates array is populated correctly!

... and this doesn't work:

$templates = $this->wire('templates');
$messageTemplates = array();
$className = self::FIELDTYPE_GROUPMAILER_MESSAGE_META; // is set to 'FieldtypeMessageMeta'

foreach ($templates as $t) {
    foreach ($t->fields as $f) {
        if ($f->type instanceof $className) {
            $messageTemplates[] = $t->name;
            break;
        }
    }
}
// $messageTemplates array is empty!

 

Link to comment
Share on other sites

The self::FIELDTYPE_GROUPMAILER_MESSAGE_META is suspicious, where do you have this code, what class is it in and in what namespace?

I put this in ready.php with and it works fine - note that I used \ProcessWire\FieldtypeEmail:

<?php namespace ProcessWire;

class G {

    private const CLASS_NAME = '\ProcessWire\FieldtypeEmail';

    public function __construct(){
        $templates = \ProcessWire\wire('templates');
        $messageTeplates = array();
        // both of these two below work fine
        $className = '\ProcessWire\FieldtypeEmail';
        // $className = self::CLASS_NAME;

        foreach ($templates as $t) {
            foreach ($t->fields as $f) {
                if ($f->type instanceof $className) {
                    $messageTeplates[] = $t->name;
                    break;
                }
            }
        }

        echo count($messageTeplates);
    }
}

new G();
exit;

Btw you have a typo in $messageTeplates".

Link to comment
Share on other sites

Apparently "instanceof" doesn't allow constants, strings, or expressions, while is_a() happily accepts all of those. This is news to me, and I'm not entirely sure of the behind the scenes logic, but it probably has something to do with instanceof being a language construct (those sometimes behave a little bit unexpectedly) – or it might simply be a performance optimization. After all instanceof is much better in terms of performance than is_a().

Use variables or literal class names instead – or if you really have to, use the workaround provided by @tpr above, i.e. store the constant value to a variable before use ?

  • Like 3
Link to comment
Share on other sites

1 hour ago, kongondo said:

Isn't this (and similar) superfluous? You are already in the ProcessWire namespace.

Apparently not, my snippet fails when I exclude ProcessWire from it.

1 hour ago, teppo said:

Apparently "instanceof" doesn't allow constants, strings, or expressions

Are you referring to the #5 example here? To my understanding it's the "variable being tested", and not the class name (after the "instanceof"):

http://php.net/manual/en/language.operators.type.php

Edit: I see, when using the constant with the instanceof directly it generates an error.

1 hour ago, teppo said:

use the workaround provided by @tpr above, i.e. store the constant value to a variable before use

He is already doing that ?

@Gadgetto Could you post the whole file? Probably we could find what's happening.

 

  • Like 1
Link to comment
Share on other sites

Just had a look at what PhpStorm offered as abbreviation, and it worked:

private const CLASS_NAME = FieldtypeEmail::class;

// or 
$className = FieldtypeEmail::class;

(it would add a "use" statement if necessary but in this case it didn't as the namespace was already ProcessWire)

Link to comment
Share on other sites

3 hours ago, tpr said:

The self::FIELDTYPE_GROUPMAILER_MESSAGE_META is suspicious, where do you have this code, what class is it in and in what namespace?

This is correctly defined in class body and the debugger confirms it holds the correct string "FieldtypeMessageMeta"

3 hours ago, tpr said:

I put this in ready.php with and it works fine - note that I used \ProcessWire\FieldtypeEmail

OK - this is strange: changing the const definition to

 const FIELDTYPE_GROUPMAILER_MESSAGE_META = '\Processwire\FieldtypeMessageMeta';

... it works as expected! Why is this?

My class file is already namespaced correctly!

 

Link to comment
Share on other sites

5 minutes ago, Gadgetto said:

My class file is already namespaced correctly!

I think it's OK. PHP shouldn't assume that the instance you are checking is in the current namespace, so you should clearly state which one to check against.

Link to comment
Share on other sites

BTW - this works perfectly without \Processwire  if I use the class name directly:

if ($f->type instanceof FieldtypeMessageMeta) {
Edited by Gadgetto
@adrian: you got me by a few seconds ... :)
Link to comment
Share on other sites

5 minutes ago, adrian said:

I know you need to check a constant or variable, but if you enter things directly, you don't need the namespace.

Yes. This is how I've been doing it in my modules. Typing \ProcessWire\...every time is a pain I want to avoid ?.

Link to comment
Share on other sites

16 minutes ago, adrian said:

I know you need to check a constant or variable, but if you enter things directly, you don't need the namespace. I guess it's to do with quoting FieldtypeEmail when assigning to a variable or const that causes the problem.

I use the class name many times across this class and in derivates - so using the literal class name directly would be a pain if something changes...

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...