thinkphp中,如果报错,怎么读懂提示的TRACE?

clipboard.png
以下是UserController

<?php
namespace Home\Controller;
use Think\Controller;
use Home\Model\Captcha;

class UserController extends Controller {
    public function register() {
      if (IS_POST) {  // 判断当前HTTP请求是否为POST请求
         // 1. 创建数据表操作对象
         $userTable = D('users');
         // 2. 获取表单数据
         $userName = I('post.username');
         $userPswd = I('post.password');
         $userImage = I('post.image');
         $captcha = I('post.captcha');
         // echo $userName, ', ', $userPswd, ', ', $userImage, ', ', $captcha;
         // exit;
         if (Captcha::checkCaptcha($captcha, Captcha::REGISTER_CAPTCHA)) {  // 验证码正确
           // 3. 注册
           $r = $userTable->doUserRegister($userName, $userPswd, $userImage);
           if ($r) {
              $this->success('用户注册成功!', '/user/login');
           }
        } else {  // 验证码不正确,要求用户重新填写
            $this->error('验证码不正确,请重新填写!');
        }
      } else {  // 当前HTTP请求不是POST,说明是GET请求
        // 显示视图文件
        $this->assign('view_title', '用户注册');
        $this->display();
      }
    }

    public function login() {

    }

    public function logout() {

    }

    public function changepswd() {
        // 1. 创建数据表操作对象
       $userTable = D('users');
       // 2. 获取表单数据
       $userName = 'test1';
       $oldPswd = '111';
       $newPswd = '222';
       // 3. 注册
       $r = $userTable->doChangePswd($userName, $oldPswd, $newPswd);
       dump($r);
    }

    /**
     * 创建验证码图片
     * @param  string $atype 创建的是哪一个操作的验证码,默认为'register'
     * @return [type]        [description]
     */
    public function captcha($atype = 'register') {
      switch ($atype) {
        case 'register':
          Captcha::createCaptcha(Captcha::REGISTER_CAPTCHA);
          break;
          case 'login': 
          Captcha::createCaptcha(Captcha::LOGIN_CAPTCHA);
          break;
          default:
          Captcha::createCaptcha(Captcha::REGISTER_CAPTCHA);
          break;
      }
    }

}

以下是UserModel

<?php

namespace Home\Model;
use Think\Model;

class UsersModel extends Model {
    // 当前数据表
    protected $trueTableName = "users";

    // 字段限定信息
    protected $_validate = array(
        // array('username', 'require'),
        array('password', 'require'),
        array('username', '','帐号名称已经存在!',0,'unique',1),
    );
    
    ////////////////////////////////////////////////////
    
    /**
     * 实现用户注册
     * @param  string $userName  用户名
     * @param  string $userPswd  用户密码
     * @param  string $userImage 用户头像的地址
     * @return mix            若用户注册成功,返回该记录的主键id;否则(失败)返回false
     */
    public function doUserRegister($userName, $userPswd, $userImage) {
        // // 1. 数据校验
        // if (empty($userName) || empty($userPswd)) {
        //     return false;
        // }
        if (empty($userImage)) {
            $userImage = '1.jpg';
        }
        // // 2. 判断用户是否存在(若用户已经存在,不能再注册该用户名)
        // if ($this->isUserExists($userName)) {
        //     return false;
        // }
        // 3. 实现注册操作
        $data['username'] = $userName;
        $data['password'] = $userPswd;
        $data['image'] = $userImage;
        // return $this->add($data);
        if ($this->create($data)) {   // 使用字段数据验证的话,必须显式地调用create()方法
            return $this->add();
        } 
        echo $this->getError();
        return false;
    }

    /**
     * 修改密码操作
     * @param  string $userName 用户名
     * @param  string $oldPswd  原始密码
     * @param  string $newPswd  新密码
     * @return boolean           若修改成功,返回true;否则返回false
     */
    public function doChangePswd($userName, $oldPswd, $newPswd) {
        // 1. 数据字段校验
        // 
        // 2. 判断原始密码和初始密码是否一致
        if ($oldPswd === $newPswd) {
            return false;
        }
        // 3. 验证原始密码
        if (!$this->isValidUser($userName, $oldPswd)) { // 当前不是有效用户,不能修改密码
            return false;
        }
        // 4. 修改密码
        $data['username'] = $userName;
        $data['password'] = $newPswd;
        return $this->where(array('username' => $userName))->save($data);
    }

    /**
     * 判断指定用户名的用户是否存在
     * @param  string  $userName 待判断的用户名
     * @return boolean           若用户名存在,返回true;否则返回false
     */
    public function isUserExists($userName) {
        // 1. 判断用户名是否有效
        if (empty($userName)) {
            return false;
        }
        // 2. 查询指定条件的记录个数
        $count = $this->where(array(
            'username'  =>  $userName
        ))->count();

        // 返回
        return 1 === $count;
    }

    /**
     * 判断指定用户名和密码的用户是否为有效用户
     * @param  string  $userName 用户名
     * @param  string  $userPswd 用户密码
     * @return boolean           若用户名和密码有效,则返回true;否则返回false
     */
    public function isValidUser($userName, $userPswd) {
        $count = $this->where(array(
            'username'  =>  $userName,
            'password'  =>  $userPswd,
        ))->count();
        return false !== $count;
    }
}

clipboard.png

阅读 5.2k
8 个回答

现在URL是什么样的? 你先在控制器里建立个GET test()方法,里面就return "test";

把这个调通了再调数据处理的,怀疑现在是路由上有问题。


刚发现,你压根没use那个用户model类啊。

clipboard.png

#3#2 这两行说明你在 UserController.class.php 中的 register() 方法中调用了 Model 类的 doUserRegister() 方法,但是很明显 Model 类中不存在该方法,也就是标题中显示的错误提示

前三行最重要,后面的确实不好读懂。

楼主这个找一下doUserRegister这个方法在哪里定义的,大小写是否正确,在哪里使用了,问题就出在这些地方。

方法可以写在控制器,可以写在模型中,看你怎么用,写在控制器中,如果是控制器自己使用的,使用的时候加个$this->...

如果是写在模型中,在控制器中使用的时候,要用D()方法来实例化那个模型,而不能用M()方法。

看了下,没发现什么问题!
把controller和model的文件全名及存放位置发出来呢!

正常的错误应该能定位到具体的Model,对应着你的UsersModel
clipboard.png

问题应该是出在你D("users") 这里, 你按规则首字母大写呢 D("Users")

楼主问的是如何读懂,那么首先要明白这个TRACE就是一个调用栈的显示,调用栈就是用户从入口文件访问,然后层层include或者require框架内部的文件,框架内部再通过一些反射等PHP内置API调用用户写的控制器,控制器再调用模型和视图,所以你要看懂它,至少得把ThinkPHP这个框架的核心文件从入口文件开始看起,然后一层一层跟随他的include来看框架核心文件里面都做了什么,这样就可以根据TRACE来判断是做哪一步操作出了错,才能定位和解决错误。

trace的函数是这个
debug_backtrace
从#10开始读,也就是从下朝上看trace

use ThinkController;
use HomeModelCaptcha;
问题出在此处,命名空间
你的model是位于Home下,那么应该 use Home\Model;

直接打印D('users'),看看有没有值,里面有没有那个方法

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题