PHP:报错Methods with the same name as their class will not be constructors in a future version of PHP

为PHP版本常见问题

错误提示

Deprecated: Methods with the same name as their class will not be constructors in a future version of PHP; StringReader has a deprecated constructor in D:\phpstudy_pro\WWW\project\includes\php-gettext\streams.php on line 48

Deprecated: Methods with the same name as their class will not be constructors in a future version of PHP; gettext_reader has a deprecated constructor in D:\phpstudy_pro\WWW\project\includes\php-gettext\gettext.php on line 36

 错误分析

这些警告信息表明您正在使用的代码中有一些类构造函数的定义方式在PHP的未来版本中将不再被支持。具体来说,这些警告指的是类的方法名称与类名相同,并且它们被当作构造函数使用,这在PHP 7.x中已经被弃用,并在PHP 8.x中完全移除。

代码修改

初始代码

以streams.php为例

<?php
class StreamReader
{
  // should return a string [FIXME: perhaps return array of bytes?]
  function read($bytes)
  {
    return false;
  }

  // should return new position
  function seekto($position)
  {
    return false;
  }

  // returns current position
  function currentpos()
  {
    return false;
  }

  // returns length of entire stream (limit for seekto()s)
  function length()
  {
    return false;
  }
};

class StringReader
{
  var $_pos;
  var $_str;

  function StringReader($str = '')
  {
    $this->_str = $str;
    $this->_pos = 0;
  }

  function read($bytes)
  {
    $data = substr($this->_str, $this->_pos, $bytes);
    $this->_pos += $bytes;
    if (strlen($this->_str) < $this->_pos)
      $this->_pos = strlen($this->_str);

    return $data;
  }

  function seekto($pos)
  {
    $this->_pos = $pos;
    if (strlen($this->_str) < $this->_pos)
      $this->_pos = strlen($this->_str);
    return $this->_pos;
  }

  function currentpos()
  {
    return $this->_pos;
  }

  function length()
  {
    return strlen($this->_str);
  }
};


class FileReader
{
  var $_pos;
  var $_fd;
  var $_length;

  function FileReader($filename)
  {
    if (file_exists($filename)) {

      $this->_length = filesize($filename);
      $this->_pos = 0;
      $this->_fd = fopen($filename, 'rb');
      if (!$this->_fd) {
        $this->error = 3; // Cannot read file, probably permissions
        return false;
      }
    } else {
      $this->error = 2; // File doesn't exist
      return false;
    }
  }

  function read($bytes)
  {
    if ($bytes) {
      fseek($this->_fd, $this->_pos);

      // PHP 5.1.1 does not read more than 8192 bytes in one fread()
      // the discussions at PHP Bugs suggest it's the intended behaviour
      $data = '';
      while ($bytes > 0) {
        $chunk  = fread($this->_fd, $bytes);
        $data  .= $chunk;
        $bytes -= strlen($chunk);
      }
      $this->_pos = ftell($this->_fd);

      return $data;
    } else return '';
  }

  function seekto($pos)
  {
    fseek($this->_fd, $pos);
    $this->_pos = ftell($this->_fd);
    return $this->_pos;
  }

  function currentpos()
  {
    return $this->_pos;
  }

  function length()
  {
    return $this->_length;
  }

  function close()
  {
    fclose($this->_fd);
  }
};

// Preloads entire file in memory first, then creates a StringReader
// over it (it assumes knowledge of StringReader internals)
class CachedFileReader extends StringReader
{
  function CachedFileReader($filename)
  {
    if (file_exists($filename)) {

      $length = filesize($filename);
      $fd = fopen($filename, 'rb');

      if (!$fd) {
        $this->error = 3; // Cannot read file, probably permissions
        return false;
      }
      $this->_str = fread($fd, $length);
      fclose($fd);
    } else {
      $this->error = 2; // File doesn't exist
      return false;
    }
  }
};

问题分析

 

如上图:类名与方法名一致,故导致问题出现 ,需要将构造函数的命名从类名更改为__construct()

修改后代码 

<?php
// Simple class to wrap file streams, string streams, etc.
// seek is essential, and it should be byte stream
class StreamReader
{
  // should return a string [FIXME: perhaps return array of bytes?]
  function read($bytes)
  {
    return false;
  }

  // should return new position
  function seekto($position)
  {
    return false;
  }

  // returns current position
  function currentpos()
  {
    return false;
  }

  // returns length of entire stream (limit for seekto()s)
  function length()
  {
    return false;
  }
};

class StringReader
{
  var $_pos;
  var $_str;

  function __construct($str = '')
  {
    $this->_str = $str;
    $this->_pos = 0;
  }

  function read($bytes)
  {
    $data = substr($this->_str, $this->_pos, $bytes);
    $this->_pos += $bytes;
    if (strlen($this->_str) < $this->_pos)
      $this->_pos = strlen($this->_str);

    return $data;
  }

  function seekto($pos)
  {
    $this->_pos = $pos;
    if (strlen($this->_str) < $this->_pos)
      $this->_pos = strlen($this->_str);
    return $this->_pos;
  }

  function currentpos()
  {
    return $this->_pos;
  }

  function length()
  {
    return strlen($this->_str);
  }
};


class FileReader
{
  var $_pos;
  var $_fd;
  var $_length;

  function __construct($filename)
  {
    if (file_exists($filename)) {

      $this->_length = filesize($filename);
      $this->_pos = 0;
      $this->_fd = fopen($filename, 'rb');
      if (!$this->_fd) {
        $this->error = 3; // Cannot read file, probably permissions
        return false;
      }
    } else {
      $this->error = 2; // File doesn't exist
      return false;
    }
  }

  function read($bytes)
  {
    if ($bytes) {
      fseek($this->_fd, $this->_pos);

      // PHP 5.1.1 does not read more than 8192 bytes in one fread()
      // the discussions at PHP Bugs suggest it's the intended behaviour
      $data = '';
      while ($bytes > 0) {
        $chunk  = fread($this->_fd, $bytes);
        $data  .= $chunk;
        $bytes -= strlen($chunk);
      }
      $this->_pos = ftell($this->_fd);

      return $data;
    } else return '';
  }

  function seekto($pos)
  {
    fseek($this->_fd, $pos);
    $this->_pos = ftell($this->_fd);
    return $this->_pos;
  }

  function currentpos()
  {
    return $this->_pos;
  }

  function length()
  {
    return $this->_length;
  }

  function close()
  {
    fclose($this->_fd);
  }
};

// Preloads entire file in memory first, then creates a StringReader
// over it (it assumes knowledge of StringReader internals)
class CachedFileReader extends StringReader
{
  function __construct($filename)
  {
    if (file_exists($filename)) {

      $length = filesize($filename);
      $fd = fopen($filename, 'rb');

      if (!$fd) {
        $this->error = 3; // Cannot read file, probably permissions
        return false;
      }
      $this->_str = fread($fd, $length);
      fclose($fd);
    } else {
      $this->error = 2; // File doesn't exist
      return false;
    }
  }
};

<think>好的,我现在需要帮助用户解决在使用修复代码时遇到的错误:“Interface Product does not have constructors”。首先,我需要理解这个错误的原因。用户之前已经按照我的建议定义了一个接口Product,但可能在实例化对象时出现了问题。 首先,用户提到的错误信息是接口没有构造函数,这通常发生在尝试直接使用接口来创建实例的时候。因为接口在TypeScript或UTS中只是类型定义,不能直接实例化。用户可能在初始化数组时错误地使用了new Product()或者试图将对象字面量直接赋值给接口类型,而没有正确实现接口的结构。 接下来,我要回顾之前提供的解决方案,用户可能按照我的建议定义了Product接口,并声明了arrs3的类型为Product[]。但在初始化数组时,可能没有正确创建符合接口结构的对象,或者错误地使用了构造函数。 我需要考虑用户可能的错误代码,比如是否在初始化数组元素时没有正确匹配接口的属性,或者是否有拼写错误。例如,如果接口中定义的是price,但对象中写成了prices,就会导致类型不匹配。此外,如果用户尝试使用类似new Product()的方式来创建对象,这也是错误的,因为接口不能有构造函数。 然后,我需要检查之前提供的修复代码示例。在之前的例子中,用户正确地将对象字面量赋值给Product[]类型的数组,每个对象都有name和price属性,类型正确。所以用户可能在实现时出现了偏差,比如没有正确遵循接口的结构,或者误用了接口的实例化方法。 可能的情况是用户尝试用类(class)来代替接口(interface),但接口本身没有构造函数,而类才有。如果用户错误地将接口当作类来使用,比如使用new关键字,就会导致这个错误。这时候需要建议用户使用类或者直接使用对象字面量,并确保符合接口的结构。 接下来,我需要准备解决方案,包括两个主要方面:使用接口的正确方式和替代方案(如使用类)。同时,需要提供具体的代码示例,说明如何正确初始化数组,避免构造函数的使用。 还需要考虑用户可能的环境或语法差异,比如UTS是否有特殊的要求,或者用户是否在混合使用不同的语法结构。此外,需要强调类型注解的重要性,确保数组和元素都正确声明类型,以避免隐式的any类型推断。 最后,要总结关键点,帮助用户理解接口和类的区别,以及如何正确使用它们来避免此类错误。同时,提醒用户注意属性名称和类型的正确性,确保对象字面量与接口定义完全匹配。</think>--- ### **错误原因解析** ```typescript interface Product { name: string; price: number; } // ❌ 错误写法 let product = new Product(); // 报错Interface 没有构造函数 ``` **直接原因**:接口(`interface`)是**纯类型定义**,不是可实例化的类(`class`)。UTS/TypeScript 的接口**没有运行时实体**,无法通过 `new` 调用构造函数。 --- ### **解决方案对比** #### **方案一:改用对象字面量** ✅ 直接创建符合接口结构的对象: ```typescript let arrs3: Product[] = [ { name: "华为", price: 6999 }, // ✅ 直接创建对象 { name: "苹果", price: 9888 } ]; ``` #### **方案二:改用类(Class)** ✅ 如果需要构造函数,改用 `class` 定义: ```typescript // 定义类 class Product { name: string; price: number; constructor(name: string, price: number) { this.name = name; this.price = price; } } // 正确实例化 let arrs3 = [ new Product("华为", 6999), // ✅ 使用 new 创建实例 new Product("苹果", 9888) ]; ``` --- ### **错误对照表** | 错误场景 | 正确写法 | 核心区别 | |---------|---------|----------| | 尝试实例化接口 | 改用对象字面量或类 | 接口是类型约束,不是实体 | | 混合使用接口和类 | 统一使用接口或类 | 保持类型系统一致性 | --- ### **完整修复示例** #### 场景:使用接口 + 对象字面量 ```typescript // 定义纯类型接口 interface Product { name: string; price: number; } // 创建符合接口结构的对象数组 let arrs3: Product[] = [ { name: "华为", price: 6999 }, // ✅ 直接赋值 { name: "苹果", price: 9888 } ]; console.log(arrs3[0].name); // 输出:华为 ``` #### 场景:使用类 + 构造函数 ```typescript // 定义可实例化的类 class Product { name: string; price: number; constructor(name: string, price: number) { this.name = name; this.price = price; } } // 通过构造函数创建实例 let arrs3 = [ new Product("华为", 6999), // ✅ 合法调用 new Product("苹果", 9888) ]; console.log(arrs3[1].price); // 输出:9888 ``` --- ### **核心知识点** 1. **接口(Interface)本质**: - 纯类型约束,编译后不会生成实际代码 - 用于定义对象结构,如属性名、类型、方法签名 - 不可包含实现逻辑或构造函数 2. **类(Class)特性**: - 运行时实体,支持实例化(`new`) - 可包含构造函数、方法实现、访问修饰符等 - 编译后生成对应平台的原生类(如 iOS 的 Swift class) 3. **UTS 类型系统规则**: ```typescript // 接口类型检查是结构化的 let obj: Product = { name: "测试", price: 100 }; // ✅ 无需继承 ``` - 只要对象结构匹配接口定义,即视为合法 --- ### **开发建议** 1. **选择接口还是类**: | 场景 | 推荐方案 | |------|----------| | 纯数据模型 | 接口 + 对象字面量 | | 需要方法实现 | 类 + 构造函数 | | 跨组件复用 | 类(支持继承) | 2. **避免混合使用**: ```typescript // ❌ 危险操作 interface Animal { name: string; } class Dog implements Animal { name: string = "Buddy"; bark() { console.log("Woof!") } } let animals: Animal[] = [new Dog()]; (animals[0] as Dog).bark(); // 需谨慎类型断言 ``` 3. **严格类型检查**: ```typescript // 启用编译选项强制检查 // utsconfig.json { "compilerOptions": { "strictNullChecks": true, "noImplicitAny": true } } ``` 如果仍有其他具体使用场景的疑问,可以提供更多代码片段,我会给出针对性分析。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

25号底片~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值