maksim 发布的文章

公司目前正在使用一套基于 TP5的开源商城,在线上测试过程中碰到了一个问题,微信支付完成后无法进行回调更新订单状态,简单点说就是钱没了,啥也没得到。

What?这可是一个无法容忍的错误。

原本以为是微信支付配置环节出了问题,于是便去查看微信官网给出的帮助手册,又顺着流程走了一边,信心满满的又测试了一边,结果尴尬了,又损失了0.01人民币。

反复确认流程后,确认并不是配置的问题,于是便开始了百度,原来这一切都是在微信官网给出的SDK中的一段代码惹的祸,就这么一段代码让我们团队损失了接近1人民币。

//获取通知的数据
$xml = $GLOBALS['HTTP_RAW_POST_DATA'];  //  WxPay.Api.php  414 line

这段代码如果放在PHP7之前的版本是不会有任何问题的,但是在 PHP7版本中却已经__废除__了 HTTP\_RAW\_POST\_DATA

在官方文档中给了说明:

Warning This feature was DEPRECATED in PHP 5.6.0, and REMOVED as of PHP 7.0.0.

PHP5.6.0发布的时候,就已经不推荐只用这种方法,于是在PHP 社区在开发 PHP7.0的时候直接就将其废弃掉了。

而官方也给出了替代的方案,那就是php://input

php://input 是个可以访问请求的原始数据的只读流。

POST 请求的情况下,最好使用 php://input 来代替 $HTTP\_RAW\_POST\_DATA,因为它不依赖于特定的 php.ini 指令。

而且,这样的情况下 $HTTP\_RAW\_POST\_DATA 默认没有填充, 比激活 always\_populate\_raw\_post\_data潜在需要更少的内存。 enctype="multipart/form-data" 的时候 php://input 是无效的。

Note: 在 PHP 5.6 之前 php://input 打开的数据流只能读取一次; 数据流不支持 seek 操作。 不过,依赖于 SAPI 的实现,请求体数据被保存的时候, 它可以打开另一个 php://input 数据流并重新读取。 通常情况下,这种情况只是针对 POST 请求,而不是其他请求方式,比如 PUT 或者 PROPFIND。

于是我将这段代码改为了:

//获取通知的数据
$xml = file_get_contents("php://input"); //  WxPay.Api.php  414 line

最后我又以0.01人民币的代价确认修复了这个 BUG。


TITLE:
categories: PHP
date:
id: 1


当一个方法在类定义内部被调用时,有一个可用的伪变量 $this。$this 是一个到主叫对象的引用(通常是该方法所从属的对象,但如果是从第二个对象静态调用时也可能是另一个对象)。

<?php
class SimpleClass
{
    // property declaration
    public $var = 'a default value';

    // method declaration
    public function displayVar() {
        echo $this->var;
    }
}
?>

$this 伪变量的示例

<?php
class A
{
    function foo()
    {
        if (isset($this)) {
            echo '$this is defined (';
            echo get_class($this);
            echo ")\n";
        } else {
            echo "\$this is not defined.\n";
        }
    }
}

class B
{
    function bar()
    {
        // Note: the next line will issue a warning if E_STRICT is enabled.
        A::foo();
    }
}

$a = new A();
$a->foo();

// Note: the next line will issue a warning if E_STRICT is enabled.
A::foo();
$b = new B();
$b->bar();

// Note: the next line will issue a warning if E_STRICT is enabled.
B::bar();
?>

以上例程会输出:

$this is defined (A)

$this is not defined.

$this is defined (B)

$this is not defined.

由于静态方法不需要通过对象即可调用,所以伪变量 $this 在静态方法中不可用。用静态方式调用一个非静态方法会导致一个 E_STRICT 级别的错误。

面向对象思想


面向对象基本概念

  • 软件编程就是将我们的思维转变成计算机能够识别语言的一个过程

思维

  • 面向对象(Object Oriented,OO)是软件开发方法
  • 面向对象是相向对象是一种对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后的产物。
  • Object Oriented Programming-OOP ——面向对象编程

面向对象


面向对象和面向过程区别

  • 面向对象是相对面向过程而言
  • 面向对象和面向过程都是一种思想
  • 面向过程

    • 强调的是功能行为
    • 关注的是解决问题需要哪些步骤
  • 面向对象

    • 将功能封装进对象,强调具备了功能的对象
    • 关注的是解决问题需要哪些对象
  • 示例
  • 把衣服放进洗衣机

    • 面向过程

      • 打开洗衣机
      • 放进去衣服
      • 关闭洗衣机
    • 面向对象

      • 洗衣机-打开
      • 洗衣机-存储
      • 洗衣机-关闭
  • 现实生活中我们是如何应用面相对象思想的

    • 想打电话\发短信
    • 去饭店吃饭
    • 汽车坏了
    • 买电脑
    • 包工头
    • 女朋友
    • 面试

面向对象的特点

  • 是一种符合人们思考习惯的思想
  • 可以将复杂的事情简单化
  • 将程序员从执行者转换成了指挥者
  • 完成需求时:

    • 先要去找具有所需的功能的对象来用。
    • 如果该对象不存在,那么创建一个具有所需功能的对象。
    • 这样简化开发并提高复用。

类与对象


类与对象的关系

面向对象的核心就是对象,那怎么创建对象?

  • OC中创建对象比较复杂, 首先要理解一个概念叫做类.
  • 现实生活中是根据一份描述,一份模板创建对象,编程语言也一样,也必须先有一份描述,在这个描述中说清楚将来创建出来的对象有哪些属性和行为

OC中述事物通过类的形式体现,类是多个同种类型事物的抽象,概念上的定义。

房子

造车

  • OC中的类相当于图纸,用来描述一类事物。也就是说,要想创建对象,必须先有类
  • OC利用类来创建对象,对象是类的具体存在, 因此面向对象解决问题应该是先考虑需要设计哪些类,再利用类创建多少个对象

类的设计


如何设计一个类

  • 生活中描述事物无非就是描述事物的名称/属性行为

    • 如:人有身高,体重等属性,有说话,打架等行为。

      事物名称(类名):人(Person)
      属性:身高(height)、年龄(age)
      行为(功能):跑(run)、打架(fight)
  • OC中用类来描述事物也是如此

    • 属性:对应类中的成员变量。
    • 行为:对应类中的成员方法。
  • 定义类其实在定义类中的成员(成员变量和成员方法)

如何分析一个类

  • 一般名词都是类(名词提炼法)

    • 飞机发射两颗炮弹摧毁了8辆装甲车

      飞机
      炮弹
      装甲车
      
    • 隔壁老王在公车上牵着一条叼着热狗的草泥马

      老王
      热狗
      草泥马
      
  • 拥有相同(或者类似)属性(状态特征)和行为(能干什么事)的对象都可以抽像成为一个类

第一个OC类


如何声明一个类

格式

声明

注意:

  • 1.必须以@interface开头,@end结尾
  • 2.成员变量的声明,必须写在@interface与@end之间的大括号中
  • 3.方法的声明必须在{}下面,不能写在{}中

如何实现一个类

格式

@implementation MyClass

- (id)initWithString:(NSString *)aName
{
    //写代码处
}

+ (MyClass *)myClassWithString:(NSString *)aName
{
    //写代码处
}

@end

注意:

  • 必须以@implementation开头,@end结尾
  • 类名必须和声明的一致

如何创建一个对象

用类的方式告诉计算机,我们需要一个什么样的对象,之后我们要在程序中使用这个对象,就必须先创建一个对象

创建

注意[Car new];做了三件事

  • 1.在堆内存中开辟了一块新的存储空间
  • 2.初始化成员变量(写在类声明大括号中的属性就叫成员变量,也叫实例变量)
  • 3.返回指针地址

消息机制

  • 使用对象调用方法就是OC中的消息机制
  • OC中调用方法的格式:[类名或者对象名 方法名];

消息机制

对象的注意点

  • 可以通过 对象->对象成员(注意声明属性为:@public) 的方式访问对象中的成员,
  • 每一个对象中都有一份属于自己的属性。
  • 对其中一个对象的成员进行了修改。和另一个对象没有关系

对象方法的声明和实现


对象方法声明

格式

2023-04-11T09:22:24.png

特征

  • 对象方法以-开头如 -(void)xx;
  • 对象方法只能由对象来调用
  • 对象方法中可以访问当前对象的成员变量
  • 调用格式 [对象名 对象方法名];

示例

//声明没有返回值的对象方法
- (void)method;
//声明有返回值的对象方法
- (int)method;
//声明有返回值有参数的对象方法
- (int)method: (int)var;
//声明有返回值有多个参数的对象方法
- (int)method: (int)var1 andVar2: (int)var2;

对象方法实现

  • 必须写在以@implementation开头,@end之间
  • 在声明的后面加上{}即表示实现
  • 将需要实现的代码写在{}中

类方法的声明和实现


类方法声明

格式

  • 将对象方法-号变为+号

特征

  • 类方法以+开头 如+(void)put;
  • 类方法只能由类来调用
  • 类方法中不能访问实例(成员)变量,因为类方法由类来调用,并没有创建存储空间 来存储类中的成员变量。

类方法的好处:

  • 不依赖于对象,执行效率更高;
  • 能用类方法解决的问题,尽量使用类方法;

类方法的场合:

  • 当方法内部不需要使用到成员变量时,可以改为类方法
  • 类方法一般用于编写工具方法

示例

//声明没有返回值的方法
+ (void)method;
//声明有返回值的方法
+ (int)method;
//声明有返回值有参数的方法
+ (int)method: (int)var;
//声明有返回值有多个参数的方法
+ (int)method: (int)var1 andVar2: (int)var2;

类方法实现

+ 必须卸载以@implementation开头,@end之间
+ 在声明的后面加上{}即表示实现
+ 讲需要实现的代码写在{}中

对象方法和类方法区别

对象方法

  • 对象方法是属于对象的
  • 以减号-开头
  • 只能让对象调用,没有对象,这个方法根本不可能被执行
  • 对象方法能访问实例变量(成员变量)
  • 对象方法中可以调用当前对象的对象方法
  • 对象方法中可以调用其他对象的对象方法
  • 对象方法中部可以调用类方法

类方法

  • 类方法是属于类的
  • 以加号+开头
  • 只能用类名调用,对象不能调用
  • 类方法中不能直接访问实例变量(成员变量)
  • 类方法中不能直接调用对象方法,要想调用对象方法,该对象必须通过参数传入。

使用场合:

  • 当不需要访问成员变量的时候,尽量用类方法

类方法和对象方法可以同名

对象的存储细节

对象的存储细节

类创建对象,每个对象在内存中都占据一定的存储空间,每个对象都有一份属于自己的单独的成员变量,所有的对象公用类的成员方法,方法在整个内存中只有一份,类本身在内存中占据一份存储空间,类的方法存储于此。

对象存储


isa指针

  • 每一个对象都包含一个isa指针,这个指针指向当前对象所属的类。
  • [p eat];表示给p所指向的对象发送一条eat消息,调用对象的eat方法,此时对象会顺着内部的isa指针找到存 储于类中的方法,执行。
  • isa是对象中的隐藏指针,指向创建这个对象的类。
  • 通过isa指针我们可以在运行的时候知道当前对象是属于那个Class(类)的

isa指针


使用一个类创建多个对象

Car *car1 = [Car new];
Car *car2 = [Car new]

2023-04-11T09:23:37.png

函数与方法对比

对象方法:

  • (1)对象方法的实现只能写在@implementation...@end中,对象方法的声明只能写在 @interface...@end中间
  • (2)对象方法都以-号开头,类方法都以+号开头
  • (3)对象方法只能由对象来调用,类方法只能由类来调用,不能当做函数一样调用
  • (4)函数属于整个文件,可以写在文件中的任何位置,包括@implementation...@end中,但写在 @interface...@end会无法识别,函数的声明可以在main函数内部也可以在main函数外部。
  • (5)对象方法归类\对象所有

函数:

  • 所有的函数都是平行的
  • 函数不存在隶属关系
  • 使用的时候可以直接调用
  • 不可以访问对象中的成员变量

常见错误

  • @interface @end和@implementation @end不能嵌套包含
  • OC是弱语法,可以只有@implementation,但实际开发中千万不要这样。
  • 只有类的声明没有类的实现 ,只有@interface没有@implementation时,程序编译能够通过
  • 漏写@end
  • 两个类的对象声明顺序(可以把顺序打乱)
  • 成员变量没有写在{}里
  • 方法的声明写在了{}里面
  • 在声明时不能对类的成员变量进行初始化,请注意成员变量不能脱离对象而独立存在
  • 方法无法像函数那样的调用
  • 成员变量和方法不能用static等关键字修饰,不要和c语言混淆
  • 类的实现可以写在mian函数后面,在使用之前只要有声明就可以

本小节知识点

  1. 如何创建Objective-C项目
  2. 对比#import和#include区别
  3. NSLog 和printf区别
  4. “@”的使用方法
  5. NS前缀

如何创建Objective-C项目

创建工程

create project

select commoand line

![select object-c]

查看结果运行结果


#import 和 #include区别

#import与#include的类似,都是把其后面的文件拷贝到该指令所在的地方
#import可以自动防止重复导入
#import <> 用于包含系统文件
#import""用于包含本项目中的文件
#import , 告诉编译器找到并处理名为Foundation.h文件,这是一个系统文件,#import表示将该文件的信息导入到程序中。
框架地址: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneO S.sdk/System/Library/Frameworks/

NSLog 和printf区别

NSLog是Foundation框架􏰀供的Objective-C日志输出函数,与标准C中的printf函数类似,并可以格式化输出。
NSLog传递进去的格式化字符是NSString的对象,而不是char *这种字符串指针
NSLog输出的内容中会自动包含一些系统信息
NSLog输出的内容会自动换行
//NSLog声明在NSObjCRuntime.h中
//声明:void NSLog(NSString *format, ...);
NSLog(@"this is a test"); //打印一个字符串
NSString *str = @"hello chendehao!";
NSLog(@"string is:%@",str);//使用占位符,%@表示打印一个对象,%@ OC特有的
NSLog(@"x=%d, y=%d",10,20);//使用多个占位符,%d表示整型数

“@”的使用方法

@"" 这个符号表示将一个C的字符串转化为OC中的字符串对象NSString.
@符号 OC中大部分的关键字都是以@开头的,比如@interface,@implementation,@end @class等。

NS前缀

NS来自于NeXTStep的一个软件 NeXT Software
OC中不支持命名空间(namespace)
NS是为了避免命名冲突而给的前缀
看到NS前缀就知道是Cocoa中的系统类的名称 

问题1:#import和#include有什么区别?

答:
1.import 的功能和 include一样, 是将右边的文件拷贝到当前import的位置.
2.import作用:为了降低程序员的负担, 防止重复导入, 避免程序员去书写头文件卫士
3.import优点: 会自动防止重复拷贝

问题2:printf和NSLog有什么区别?

答:
1.NSLog会自动换行
2.NSLog在输出内容时会附加一些系统信息
3.NSLog和printf接收的参数不一样

问题3:Foundation有什么作用?

答:Foundation.h我们称之为主头文件, 主头文件中又拷贝了该工具箱中所有工具的头文件, 我们只需要导入主头文件就可以使用该工具箱中所有的工具, 避免了每次使用都要导入一个对应的头文件

工具箱的地址: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks

规律: 所有的主头文件的名称都和工具箱的名称一致,所有的主头文件都是导入了该工具箱中所有工具的头文件

本小节知识点:

  1. 源文件对比
  2. 关键字对比
  3. 数据类型对比
  4. 流行控制语句对比
  5. 面向对象新增特性
  6. 面向对象新增语法
  7. 新增异常处理

源文件对比

  • C 语言常见源文件 .h 文件, .c文件
文件扩展名源类型
.h头文件,用于存放函数声明
.cC语言源文件,用于实现头文件中声明的方法
  • OC 中源文件.h文件,.m 与.mm的实现文件
文件扩展名源类型
.h头文件,头文件包含类、方法、属性的声明
.m/.mm类的实现文件,参与编译的文件,用来实现类中声明的方法

关键词对比

  • C 语言的关键字都可以在 OC 源程序中使用
  • OC 新增呢个的关键字在使用时,注意部分关键字以“@”开头

对比图

数据类型对比

  • C 数据类型

脑图

  • OC 中的数据类型

脑图

类型描述
BOOL只有两个取值真和假
NsObject*OC 中的对象类型
id动态对象类型,万能指针
SEL选择器数据类型
block代码块数据类型
  • OC 中的类

    • Objective-C 是一种面向对象的语言,定义类时它的基本能力。
    • 那什么是类呢?类是用来描述对象的,它是一系列方法和属性的集合。
    • Objective-C 的类声明和实现包括两个部分:接口部分和实现部分
    • 想要定义方法也就是 C 语言中的函数,那么就必须先有类存在

流程控制语句对比

  • C语言中使用的流程控制语句OC中都可以应用
if 语句

switch语句

while语句

dowhile语句

for语句

break关键字

continue关键字
  • 增强for循环,用于快速迭代数组或者集合
  • C语言for循环
for (int i = 0; i < 10; i++){
        printf(“%d”,i);

}
  • OC增强for循环
for (NSString * name in NSArray){
        NSLog(@”%@”,name);
}

函数(方法)定义和声明对比

  • C语言中函数的声明和实现

    • 函数声明:int sum(int a,int b);
    • 函数实现:int sum(int a,int b){ return a+b; }
  • OC中的方法

    • 方法声明:- (int)sum:(int) a andB:(int) b;
    • 方法实现:- (int)sum:(int) a andB:(int )b{ return a+b; }
  • 注意: 方法只能写在类里面, 而函数可以写在任何地方

    • 对象方法,使用对象调用的方法
    • 类方法,使用类名调用的方法
对象方法

- (id)initWithString: (NSString * )name;

类方法

+ (MyClass *)createMyClassWithString: (NSString *)name;

面相对象新增特性

  • 封装性
  • 继承性
  • 多态性

object-class

面向对象新增语法

  • 属性生成器:用来简化代码

    • @property
    • @synthesize
//声明属性

@property (nonatomic,strong)NSString * name;

//合成属性

@synthesize name = _name;
  • 分类:在不修改原有类的情况下新增一个功能。

    • 分类与继承
    • 使用分类扩展类,无需子类化
@interface NSString (MyNSString)

- (NSString *) encryptWithMD5;

@end
  • 协议:类似于其他语言中的 interface

    • 使用协议声明方法
    • 协议类似于C#,java中的接口
@protocol MyProtocol

- (void)myProtocolMethod;

@end
  • Fundation框架:以后写 ios 天天会用这个东西,要花费好几天学习这一块。

    • 创建和管理集合,如数组和字典
    • 访问存储在应用中的图像和其他资源
    • 创建和管理字符串
    • 发布和观察通知
    • 创建日期和时间对象
    • 操控URL流
    • 异步执行代码

新增异常处理

  • 用于处理错误信息
  • 格式:

    • @try .... @catch .... @finally
  • 示例:
//创建对象car

Car *car = [Car new];

@try {
        //调用一个没有实现的方法
        [car test];
} @catch (NSException *exception) {
   NSLog(@"%@",exception.name);
} @finally {
        NSLog(@"继续执行!\n");
}